Tomcat-ConfigContext监听器(Context.xml,web.xml)

Tomcat的Host初始化(Context,Listener,Filter,Servlet):[url]http://donald-draper.iteye.com/blog/2327174[/url]
Host作为Engine的子容器,在Host中有两个变量为StandardContext和
configClass,StandardContext在前文中我们已经讲过了,
public class StandardHost extends ContainerBase implements Host {
/**
* 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";
}

现在我们,来看看org.apache.catalina.startup.ContextConfig都做了些什么?
public class ContextConfig implements LifecycleListener {
/**
* 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 final Properties authenticators;
/**
* The list of JARs that will be skipped when scanning a web application
* for JARs. This means the JAR will not be scanned for web fragments, SCIs,
* annotations or classes that match @HandlesTypes.
*/
private static final Set<String> pluggabilityJarsToSkip =
new HashSet<String>();

static {
// Load our mapping properties for the standard authenticators
Properties props = new Properties();
InputStream is = null;
try {
//加载Authenticators.properties
is = ContextConfig.class.getClassLoader().getResourceAsStream(
"org/apache/catalina/startup/Authenticators.properties");
if (is != null) {
props.load(is);
}
}
authenticators = props;
//Load the list of JARS to skip
addJarsToSkip(Constants.DEFAULT_JARS_TO_SKIP);
addJarsToSkip(Constants.PLUGGABILITY_JARS_TO_SKIP);
}
/**
* 每个Host的默认web.xml配置缓存
*/
protected static final Map<Host,DefaultWebXmlCacheEntry> hostWebXmlCache =
new ConcurrentHashMap<Host,DefaultWebXmlCacheEntry>();
//当容器生命周期变化时,激发
public void lifecycleEvent(LifecycleEvent event) {

// Identify the context we are associated with
try {
//获取Context
context = (Context) event.getLifecycle();
}

if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
//开始配置
configureStart();
} else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
beforeStart();
} else if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) {
//context设置docBase
if (originalDocBase != null) {
context.setDocBase(originalDocBase);
}
} else if (event.getType().equals(Lifecycle.CONFIGURE_STOP_EVENT)) {
configureStop();
} else if (event.getType().equals(Lifecycle.AFTER_INIT_EVENT)) {
//初始化
init();
} else if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT)) {
destroy();
}
//处理Context的AFTER_INIT_EVENT事件
protected void init() {
// Called from StandardContext.init()
//创建一个解析Context.xml的Digester
Digester contextDigester = createContextDigester();
contextDigester.getParser();
if (log.isDebugEnabled())
log.debug(sm.getString("contextConfig.init"));
context.setConfigured(false);
ok = true;
//解析Context.xml文件
contextConfig(contextDigester);
createWebXmlDigester(context.getXmlNamespaceAware(),
context.getXmlValidation());
}
//获取Context.xml,与Digester关联
protected void contextConfig(Digester digester) {

// Open the default context.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()) {
File defaultContextFile = new File(defaultContextXml);
if (!defaultContextFile.isAbsolute()) {
defaultContextFile =new File(getBaseDir(), defaultContextXml);
}
if (defaultContextFile.exists()) {
try {
URL defaultContextUrl = defaultContextFile.toURI().toURL();
processContextConfig(digester, defaultContextUrl);
} catch (MalformedURLException e) {
log.error(sm.getString(
"contextConfig.badUrl", defaultContextFile), e);
}
}

File hostContextFile = new File(getHostConfigBase(), Constants.HostContextXml);
if (hostContextFile.exists()) {
try {
URL hostContextUrl = hostContextFile.toURI().toURL();
processContextConfig(digester, hostContextUrl);
} catch (MalformedURLException e) {
log.error(sm.getString(
"contextConfig.badUrl", hostContextFile), e);
}
}
}
if (context.getConfigFile() != null)
processContextConfig(digester, context.getConfigFile());

}
//处理context.xml.
protected void processContextConfig(Digester digester, URL contextXml) {
if (log.isDebugEnabled())
log.debug("Processing context [" + context.getName()
+ "] configuration file [" + contextXml + "]");
InputSource source = null;
InputStream stream = null;
try {
source = new InputSource(contextXml.toString());
URLConnection xmlConn = contextXml.openConnection();
xmlConn.setUseCaches(false);
stream = xmlConn.getInputStream();
}
try {
source.setByteStream(stream);
digester.setClassLoader(this.getClass().getClassLoader());
digester.setUseContextClassLoader(false);
digester.push(context.getParent());
digester.push(context);
XmlErrorHandler errorHandler = new XmlErrorHandler();
digester.setErrorHandler(errorHandler);
digester.parse(source);
if (log.isDebugEnabled()) {
log.debug("Successfully processed context [" + context.getName()
+ "] configuration file [" + contextXml + "]");
}
}
}
}

从上面可以看出Lifecycle.AFTER_INIT_EVENT触发init方法,init方法,首先创建一个
解析Context.xml文件的Digester,然后待在Context.xml文件,由Digester去解析处理;
下面来看一下Lifecycle.BEFORE_START_EVENT触发的方法beforeStart:
//Process a "before start" event for this Context.
protected synchronized void beforeStart() {
try {
//调整docBase.
fixDocBase();
}
//调整antiLockingDocBase
antiLocking();
}
//调整docBase.
protected void fixDocBase()
throws IOException {
//获取StandardHost
Host host = (Host) context.getParent();
String appBase = host.getAppBase();
File canonicalAppBase = new File(appBase);
if (canonicalAppBase.isAbsolute()) {
canonicalAppBase = canonicalAppBase.getCanonicalFile();
} else {
canonicalAppBase =
new File(getBaseDir(), 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;
}
ContextName cn = new ContextName(path, context.getWebappVersion());
docBase = cn.getBaseName();
}
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;
ContextName cn = new ContextName(context.getPath(),
context.getWebappVersion());
String pathName = cn.getBaseName();
boolean unpackWARs = true;
if (host instanceof StandardHost) {
unpackWARs = ((StandardHost) host).isUnpackWARs();
if (unpackWARs && context instanceof StandardContext) {
unpackWARs = ((StandardContext) context).getUnpackWAR();
}
}
if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory()) {
URL war = UriUtil.buildJarUrl(new File(docBase));
if (unpackWARs) {
docBase = ExpandWar.expand(host, war, pathName);
file = new File(docBase);
docBase = file.getCanonicalPath();
if (context instanceof StandardContext) {
//设置StandardContext的docBase
((StandardContext) context).setOriginalDocBase(origDocBase);
}
} else {
ExpandWar.validate(host, war, pathName);
}
} else {
File docDir = new File(docBase);
if (!docDir.exists()) {
File warFile = new File(docBase + ".war");
if (warFile.exists()) {
URL war = UriUtil.buildJarUrl(warFile);
if (unpackWARs) {
docBase = ExpandWar.expand(host, war, pathName);
file = new File(docBase);
docBase = file.getCanonicalPath();
} else {
docBase = warFile.getCanonicalPath();
ExpandWar.validate(host, war, pathName);
}
}
if (context instanceof StandardContext) {
((StandardContext) context).setOriginalDocBase(origDocBase);
}
}
}
context.setDocBase(docBase);

}
//调整antiLockingDocBase
protected void antiLocking() {

if ((context instanceof StandardContext)
&& ((StandardContext) context).getAntiResourceLocking()) {

Host host = (Host) context.getParent();
String appBase = host.getAppBase();
String docBase = context.getDocBase();
originalDocBase = docBase;
File docBaseFile = new File(docBase);
if (!docBaseFile.isAbsolute()) {
File file = new File(appBase);
if (!file.isAbsolute()) {
file = new File(getBaseDir(), appBase);
}
docBaseFile = new File(file, docBase);
}
String path = context.getPath();
ContextName cn = new ContextName(path, context.getWebappVersion());
docBase = cn.getBaseName();
if (originalDocBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {
antiLockingDocBase = new File(
System.getProperty("java.io.tmpdir"),
deploymentCount++ + "-" + docBase + ".war");
} else {
antiLockingDocBase = new File(
System.getProperty("java.io.tmpdir"),
deploymentCount++ + "-" + docBase);
}
antiLockingDocBase = antiLockingDocBase.getAbsoluteFile();

if (log.isDebugEnabled())
log.debug("Anti locking context[" + context.getName()
+ "] setting docBase to " +
antiLockingDocBase.getPath());

// Cleanup just in case an old deployment is lying around
ExpandWar.delete(antiLockingDocBase);
if (ExpandWar.copy(docBaseFile, antiLockingDocBase)) {
context.setDocBase(antiLockingDocBase.getPath());
}
}
}

从beforeStart方法,我们可以看出每个从ContextConfig,关联一个StandardContext,
而每个StandardContext都有一个父容器StandardHost。
下面来看Lifecycle.CONFIGURE_START_EVENT事件的触发方法configureStart
//处理Context的CONFIGURE_START_EVENT事件
    protected synchronized void configureStart() {
// Called from StandardContext.start()
if (log.isDebugEnabled())
log.debug(sm.getString("contextConfig.start"));
//扫描Web.xml文件,应用到web
webConfig();
if (!context.getIgnoreAnnotations()) {
//处理Listener,Filter,Servet的class,field,method,
//EJB,JSR 250类注解问题,@Resource等注解
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);
}

}
//解析WEB.XML文件,如果存在global web.xml,则以WEB——INF/WEB.XML为准,及当前WEB
    protected void webConfig() {
Set<WebXml> defaults = new HashSet<WebXml>();
//从Host获取默认WebXML,通过Digester解析,添加到defaults
defaults.add(getDefaultWebXmlFragment());
WebXml webXml = createWebXml();
//解析全局Web.xml
// Parse context level web.xml
InputSource contextWebXml = getContextWebXmlSource();
parseWebXml(contextWebXml, webXml, false);

ServletContext sContext = context.getServletContext();

// Ordering is important here

// Step 1. Identify all the JARs packaged with the application
// If the JARs have a web-fragment.xml it will be parsed at this
// point.
Map<String,WebXml> fragments = processJarsForWebFragments(webXml);

// Step 2. Order the fragments.
Set<WebXml> orderedFragments = null;
orderedFragments =
WebXml.orderWebFragments(webXml, fragments, sContext);

// Step 3. Look for ServletContainerInitializer implementations
if (ok) {
processServletContainerInitializers();
}

if (!webXml.isMetadataComplete() || typeInitializerMap.size() > 0) {
// Step 4. Process /WEB-INF/classes for annotations
if (ok) {
// Hack required by Eclipse's "serve modules without
// publishing" feature since this backs WEB-INF/classes by
// multiple locations rather than one.
NamingEnumeration<Binding> listBindings = null;
try {
try {
listBindings = context.getResources().listBindings(
"/WEB-INF/classes");
}
while (listBindings != null &&
listBindings.hasMoreElements()) {
Binding binding = listBindings.nextElement();
if (binding.getObject() instanceof FileDirContext) {
File webInfClassDir = new File(
((FileDirContext) binding.getObject()).getDocBase());
processAnnotationsFile(webInfClassDir, webXml,
webXml.isMetadataComplete());
} else {
String resource =
"/WEB-INF/classes/" + binding.getName();
try {
URL url = sContext.getResource(resource);
processAnnotationsUrl(url, webXml,
webXml.isMetadataComplete());
}
}
}
}
}

// Step 5. Process JARs for annotations - only need to process
// those fragments we are going to use
if (ok) {
processAnnotations(
orderedFragments, webXml.isMetadataComplete());
}

// Cache, if used, is no longer required so clear it
javaClassCache.clear();
}

if (!webXml.isMetadataComplete()) {
// Step 6. Merge web-fragment.xml files into the main web.xml
// file.
if (ok) {
ok = webXml.merge(orderedFragments);
}

// Step 7. Apply global defaults
// Have to merge defaults before JSP conversion since defaults
// provide JSP servlet definition.
webXml.merge(defaults);

// Step 8. Convert explicitly mentioned jsps to servlets
if (ok) {
convertJsps(webXml);
}

// Step 9. Apply merged web.xml to Context
if (ok) {
webXml.configureContext(context);
}
} else {
webXml.merge(defaults);
convertJsps(webXml);
webXml.configureContext(context);
}

// Step 9a. Make the merged web.xml available to other
// components, specifically Jasper, to save those components
// from having to re-generate it.
// TODO Use a ServletContainerInitializer for Jasper
String mergedWebXml = webXml.toXml();
sContext.setAttribute(
org.apache.tomcat.util.scan.Constants.MERGED_WEB_XML,
mergedWebXml);
if (context.getLogEffectiveWebXml()) {
log.info("web.xml:\n" + mergedWebXml);
}

// Always need to look for static resources
// Step 10. Look for static resources packaged in JARs
if (ok) {
// Spec does not define an order.
// Use ordered JARs followed by remaining JARs
Set<WebXml> resourceJars = new LinkedHashSet<WebXml>();
for (WebXml fragment : orderedFragments) {
resourceJars.add(fragment);
}
for (WebXml fragment : fragments.values()) {
if (!resourceJars.contains(fragment)) {
resourceJars.add(fragment);
}
}
processResourceJARs(resourceJars);
// See also StandardContext.resourcesStart() for
// WEB-INF/classes/META-INF/resources configuration
}

// Step 11. Apply the ServletContainerInitializer config to the
// context
if (ok) {
for (Map.Entry<ServletContainerInitializer,
Set<Class<?>>> entry :
initializerClassMap.entrySet()) {
if (entry.getValue().isEmpty()) {
context.addServletContainerInitializer(
entry.getKey(), null);
} else {
context.addServletContainerInitializer(
entry.getKey(), entry.getValue());
}
}
}
}

从上面可看出,webConfig主要是处理web.xml的解析,与全局web.xml(Context)融合的问题
下面看一下cofigStart方法中注解的处理applicationAnnotationsConfig:
// 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());
}
}

查看WebAnnotationSet的loadApplicationAnnotations函数:
//处理Listener,Filter,Servet的class,field,method,的注解
 public static void loadApplicationAnnotations(Context context) {
loadApplicationListenerAnnotations(context);
loadApplicationFilterAnnotations(context);
loadApplicationServletAnnotations(context);
}
//处理Listener的注解
protected static void loadApplicationListenerAnnotations(Context context) {
Class<?> classClass = null;
//从Context获取applicationListeners
String[] applicationListeners =
context.findApplicationListeners();
for (int i = 0; i < applicationListeners.length; i++) {
classClass = Introspection.loadClass(context,
applicationListeners[i]);
if (classClass == null) {
continue;
}
//处理Listener的class,field,method,的注解
loadClassAnnotation(context, classClass);
loadFieldsAnnotation(context, classClass);
loadMethodsAnnotation(context, classClass);
}
}
//处理Filter的注解
protected static void loadApplicationFilterAnnotations(Context context) {
Class<?> classClass = null;
FilterDef[] filterDefs = context.findFilterDefs();
for (int i = 0; i < filterDefs.length; i++) {
classClass = Introspection.loadClass(context,
(filterDefs[i]).getFilterClass());
if (classClass == null) {
continue;
}
//处理Filter的class,field,method,的注解
loadClassAnnotation(context, classClass);
loadFieldsAnnotation(context, classClass);
loadMethodsAnnotation(context, classClass);
}
}
//处理Server的注解
protected static void loadApplicationServletAnnotations(Context context) {

Wrapper wrapper = null;
Class<?> classClass = null;
Container[] children = context.findChildren();
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof Wrapper) {

wrapper = (Wrapper) children[i];
if (wrapper.getServletClass() == null) {
continue;
}
classClass = Introspection.loadClass(context,
wrapper.getServletClass());
if (classClass == null) {
continue;
}
//处理Servet的class,field,method,的注解
loadClassAnnotation(context, classClass);
loadFieldsAnnotation(context, classClass);
loadMethodsAnnotation(context, classClass);
/* Process RunAs annotation which can be only on servlets.
* Ref JSR 250, equivalent to the run-as element in
* the deployment descriptor
*/
RunAs annotation = classClass.getAnnotation(RunAs.class);
if (annotation != null) {
wrapper.setRunAs(annotation.value());
}
}
}

}
//处理Listener的class,field,method,的注解
protected static void loadClassAnnotation(Context context,
Class<?> classClass) {
/* Process Resource annotation.
* Ref JSR 250
*/
{
Resource annotation = classClass.getAnnotation(Resource.class);
if (annotation != null) {
addResource(context, annotation);
}
}
/* Process Resources annotation.
* Ref JSR 250
*/
{
//@Resource
Resources annotation = classClass.getAnnotation(Resources.class);
if (annotation != null && annotation.value() != null) {
for (Resource resource : annotation.value()) {
addResource(context, resource);
}
}
}
/* Process EJB annotation.
* Ref JSR 224, equivalent to the ejb-ref or ejb-local-ref
* element in the deployment descriptor.
{
//@EJB
EJB annotation = classClass.getAnnotation(EJB.class);
if (annotation != null) {

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
{
//@WebServiceRef
WebServiceRef annotation = classClass
.getAnnotation(WebServiceRef.class);
if (annotation != null) {
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
*/
{
//@DeclareRoles
DeclareRoles annotation = classClass
.getAnnotation(DeclareRoles.class);
if (annotation != null && annotation.value() != null) {
for (String role : annotation.value()) {
context.addSecurityRole(role);
}
}
}
}
//处理field注解
protected static void loadFieldsAnnotation(Context context,
Class<?> classClass) {
// Initialize the annotations
Field[] fields = Introspection.getDeclaredFields(classClass);
if (fields != null && fields.length > 0) {
for (Field field : fields) {
//@Resource
Resource annotation = field.getAnnotation(Resource.class);
if (annotation != null) {
String defaultName = classClass.getName() + SEPARATOR + field.getName();
Class<?> defaultType = field.getType();
addResource(context, annotation, defaultName, defaultType);
}
}
}
}
//处理method注解
protected static void loadMethodsAnnotation(Context context,
Class<?> classClass) {
// Initialize the annotations
Method[] methods = Introspection.getDeclaredMethods(classClass);
if (methods != null && methods.length > 0) {
for (Method method : methods) {
//@Resource
Resource annotation = method.getAnnotation(Resource.class);
if (annotation != null) {
if (!Introspection.isValidSetter(method)) {
throw new IllegalArgumentException(sm.getString(
"webAnnotationSet.invalidInjection"));
}
String defaultName = classClass.getName() + SEPARATOR +
Introspection.getPropertyName(method);

Class<?> defaultType =
(method.getParameterTypes()[0]);
addResource(context, annotation, defaultName, defaultType);
}
}
}
}

从分析注解的配置可以看出,实际上就是先从Context获取Lisenters,Filters和Servlets,
然后分别处理Lisenters,Filters和Servlets的Class,Field和Method的注解。
下面来看Lifecycle.AFTER_START_EVENT事件的触发方法configureStart
//context设置docBase
 if (originalDocBase != null) {
context.setDocBase(originalDocBase);
}

总结:
[color=blue]从以上分析每个Host,关联一个ContextConfig和StandardContext,而ContextConfig关联于StandardContext;ContextConfig其实是一个LifecycleListener可以监听StandardContext容器的声明周期变化;当处于AFTER_INIT_EVEN状态时,加载Context.xml文件,通过Digester解析;当处于BEFORE_START_EVENT状态时,docbase;当处于CONFIGURE_START_EVENT状态时,加载Web.xml配置(欢迎页面,参数,listeners,filters,Servlet,filters-Maping,Servlet-Maping,SessionConfig,errorPage等),然后处理listeners,filters,Servlet的注解等;当处于AFTER_START_EVENT状态时,设置context的docBase,自此完成web应用的context.xml,web.xml的初始化工作。[/color]

附:
//Web.xml配置文件类
/**
* Representation of common elements of web.xml and web-fragment.xml. Provides
* a repository for parsed data before the elements are merged.
* Validation is spread between multiple classes:
* The digester checks for structural correctness (eg single login-config)
* This class checks for invalid duplicates (eg filter/servlet names)
* StandardContext will check validity of values (eg URL formats etc)
*/
public class WebXml {
// context-param
// TODO: description (multiple with language) is ignored
private Map<String,String> contextParams = new HashMap<String,String>();
public void addContextParam(String param, String value) {
contextParams.put(param, value);
}
public Map<String,String> getContextParams() { return contextParams; }

// filter
// TODO: Should support multiple description elements with language
// TODO: Should support multiple display-name elements with language
// TODO: Should support multiple icon elements
// TODO: Description for init-param is ignored
private Map<String,FilterDef> filters =
new LinkedHashMap<String,FilterDef>();
//添加Filter
public void addFilter(FilterDef filter) {
if (filters.containsKey(filter.getFilterName())) {
// Filter names must be unique within a web(-fragment).xml
throw new IllegalArgumentException(
sm.getString("webXml.duplicateFilter",
filter.getFilterName()));
}
filters.put(filter.getFilterName(), filter);
}
public Map<String,FilterDef> getFilters() { return filters; }

// filter-mapping
private Set<FilterMap> filterMaps = new LinkedHashSet<FilterMap>();
private Set<String> filterMappingNames = new HashSet<String>();
//添加FilterMaping
public void addFilterMapping(FilterMap filterMap) {
filterMaps.add(filterMap);
filterMappingNames.add(filterMap.getFilterName());
}
public Set<FilterMap> getFilterMappings() { return filterMaps; }

// listener
// TODO: description (multiple with language) is ignored
// TODO: display-name (multiple with language) is ignored
// TODO: icon (multiple) is ignored
private Set<String> listeners = new LinkedHashSet<String>();
//添加Listeners
public void addListener(String className) {
listeners.add(className);
}
public Set<String> getListeners() { return listeners; }

// servlet
// TODO: description (multiple with language) is ignored
// TODO: display-name (multiple with language) is ignored
// TODO: icon (multiple) is ignored
// TODO: init-param/description (multiple with language) is ignored
// TODO: security-role-ref/description (multiple with language) is ignored
private Map<String,ServletDef> servlets = new HashMap<String,ServletDef>();
//添加Servlet
public void addServlet(ServletDef servletDef) {
servlets.put(servletDef.getServletName(), servletDef);
if (overridable) {
servletDef.setOverridable(overridable);
}
}
public Map<String,ServletDef> getServlets() { return servlets; }

// servlet-mapping
private Map<String,String> servletMappings = new HashMap<String,String>();
private Set<String> servletMappingNames = new HashSet<String>();
//添加Servlet-mapping
public void addServletMapping(String urlPattern, String servletName) {
String oldServletName = servletMappings.put(urlPattern, servletName);
if (oldServletName != null) {
// Duplicate mapping. As per clarification from the Servlet EG,
// deployment should fail.
throw new IllegalArgumentException(sm.getString(
"webXml.duplicateServletMapping", oldServletName,
servletName, urlPattern));
}
servletMappingNames.add(servletName);
}
public Map<String,String> getServletMappings() { return servletMappings; }

// session-config
// Digester will check there is only one of these
private SessionConfig sessionConfig = new SessionConfig();
public void setSessionConfig(SessionConfig sessionConfig) {
this.sessionConfig = sessionConfig;
}
public SessionConfig getSessionConfig() { return sessionConfig; }

// mime-mapping
private Map<String,String> mimeMappings = new HashMap<String,String>();
public void addMimeMapping(String extension, String mimeType) {
mimeMappings.put(extension, mimeType);
}
public Map<String,String> getMimeMappings() { return mimeMappings; }
// welcome-file-list
private Set<String> welcomeFiles = new LinkedHashSet<String>();
public void addWelcomeFile(String welcomeFile) {
if (replaceWelcomeFiles) {
welcomeFiles.clear();
replaceWelcomeFiles = false;
}
welcomeFiles.add(welcomeFile);
}
public Set<String> getWelcomeFiles() { return welcomeFiles; }

// error-page
private Map<String,ErrorPage> errorPages = new HashMap<String,ErrorPage>();
public void addErrorPage(ErrorPage errorPage) {
errorPages.put(errorPage.getName(), errorPage);
}
public Map<String,ErrorPage> getErrorPages() { return errorPages; }

// Digester will check there is only one jsp-config
// jsp-config/taglib or taglib (2.3 and earlier)
private Map<String,String> taglibs = new HashMap<String,String>();
public void addTaglib(String uri, String location) {
if (taglibs.containsKey(uri)) {
// Taglib URIs must be unique within a web(-fragment).xml
throw new IllegalArgumentException(
sm.getString("webXml.duplicateTaglibUri", uri));
}
taglibs.put(uri, location);
}
public Map<String,String> getTaglibs() { return taglibs; }

// jsp-config/jsp-property-group
private Set<JspPropertyGroup> jspPropertyGroups =
new LinkedHashSet<JspPropertyGroup>();
public void addJspPropertyGroup(JspPropertyGroup propertyGroup) {
jspPropertyGroups.add(propertyGroup);
}
public Set<JspPropertyGroup> getJspPropertyGroups() {
return jspPropertyGroups;
}

// security-constraint
// TODO: Should support multiple display-name elements with language
// TODO: Should support multiple description elements with language
private Set<SecurityConstraint> securityConstraints =
new HashSet<SecurityConstraint>();
public void addSecurityConstraint(SecurityConstraint securityConstraint) {
securityConstraints.add(securityConstraint);
}
public Set<SecurityConstraint> getSecurityConstraints() {
return securityConstraints;
}

// login-config
// Digester will check there is only one of these
private LoginConfig loginConfig = null;
public void setLoginConfig(LoginConfig loginConfig) {
this.loginConfig = loginConfig;
}
public LoginConfig getLoginConfig() { return loginConfig; }

// security-role
// TODO: description (multiple with language) is ignored
private Set<String> securityRoles = new HashSet<String>();
public void addSecurityRole(String securityRole) {
securityRoles.add(securityRole);
}
public Set<String> getSecurityRoles() { return securityRoles; }


// resource-ref
// TODO: Should support multiple description elements with language
private Map<String,ContextResource> resourceRefs =
new HashMap<String,ContextResource>();
public void addResourceRef(ContextResource resourceRef) {
if (resourceRefs.containsKey(resourceRef.getName())) {
// resource-ref names must be unique within a web(-fragment).xml
throw new IllegalArgumentException(
sm.getString("webXml.duplicateResourceRef",
resourceRef.getName()));
}
resourceRefs.put(resourceRef.getName(), resourceRef);
}
public Map<String,ContextResource> getResourceRefs() {
return resourceRefs;
}

// resource-env-ref
// TODO: Should support multiple description elements with language
private Map<String,ContextResourceEnvRef> resourceEnvRefs =
new HashMap<String,ContextResourceEnvRef>();
public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) {
if (resourceEnvRefs.containsKey(resourceEnvRef.getName())) {
// resource-env-ref names must be unique within a web(-fragment).xml
throw new IllegalArgumentException(
sm.getString("webXml.duplicateResourceEnvRef",
resourceEnvRef.getName()));
}
resourceEnvRefs.put(resourceEnvRef.getName(), resourceEnvRef);
}
public Map<String,ContextResourceEnvRef> getResourceEnvRefs() {
return resourceEnvRefs;
}
}

//处理XML的Digester
public class Digester extends DefaultHandler2 {
/**
* The parameters stack being utilized by CallMethodRule and
* CallParamRule rules.
*/
protected ArrayStack<Object> params = new ArrayStack<Object>();
/**
* The stack of body text string buffers for surrounding elements.
*/
protected ArrayStack<StringBuilder> bodyTexts =
new ArrayStack<StringBuilder>();

/**
* 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 empty constructor.
*/
public Digester(XMLReader reader) {
super();
this.reader = reader;
}
/**
* 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<Object> namedStack = stacksByName.get(stackName);
if (namedStack == null) {
namedStack = new ArrayStack<Object>();
stacksByName.put(stackName, namedStack);
}
namedStack.push(value);
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值