View | Details | Raw Unified | Return to bug 46264
Collapse All | Expand All

(-)a/java/org/apache/catalina/Container.java (-479 / +496 lines)
Lines 1-479 Link Here
1
/*
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
17
18
18
19
package org.apache.catalina;
19
package org.apache.catalina;
20
20
21
21
22
import java.beans.PropertyChangeListener;
22
import java.beans.PropertyChangeListener;
23
import java.io.IOException;
23
import java.io.IOException;
24
24
25
import javax.management.ObjectName;
25
import javax.management.ObjectName;
26
import javax.naming.directory.DirContext;
26
import javax.naming.directory.DirContext;
27
import javax.servlet.ServletException;
27
import javax.servlet.ServletException;
28
28
29
import org.apache.catalina.connector.Request;
29
import org.apache.catalina.connector.Request;
30
import org.apache.catalina.connector.Response;
30
import org.apache.catalina.connector.Response;
31
import org.apache.juli.logging.Log;
31
import org.apache.juli.logging.Log;
32
32
33
33
34
/**
34
/**
35
 * A <b>Container</b> is an object that can execute requests received from
35
 * A <b>Container</b> is an object that can execute requests received from
36
 * a client, and return responses based on those requests.  A Container may
36
 * a client, and return responses based on those requests.  A Container may
37
 * optionally support a pipeline of Valves that process the request in an
37
 * optionally support a pipeline of Valves that process the request in an
38
 * order configured at runtime, by implementing the <b>Pipeline</b> interface
38
 * order configured at runtime, by implementing the <b>Pipeline</b> interface
39
 * as well.
39
 * as well.
40
 * <p>
40
 * <p>
41
 * Containers will exist at several conceptual levels within Catalina.  The
41
 * Containers will exist at several conceptual levels within Catalina.  The
42
 * following examples represent common cases:
42
 * following examples represent common cases:
43
 * <ul>
43
 * <ul>
44
 * <li><b>Engine</b> - Representation of the entire Catalina servlet engine,
44
 * <li><b>Engine</b> - Representation of the entire Catalina servlet engine,
45
 *     most likely containing one or more subcontainers that are either Host
45
 *     most likely containing one or more subcontainers that are either Host
46
 *     or Context implementations, or other custom groups.
46
 *     or Context implementations, or other custom groups.
47
 * <li><b>Host</b> - Representation of a virtual host containing a number
47
 * <li><b>Host</b> - Representation of a virtual host containing a number
48
 *     of Contexts.
48
 *     of Contexts.
49
 * <li><b>Context</b> - Representation of a single ServletContext, which will
49
 * <li><b>Context</b> - Representation of a single ServletContext, which will
50
 *     typically contain one or more Wrappers for the supported servlets.
50
 *     typically contain one or more Wrappers for the supported servlets.
51
 * <li><b>Wrapper</b> - Representation of an individual servlet definition
51
 * <li><b>Wrapper</b> - Representation of an individual servlet definition
52
 *     (which may support multiple servlet instances if the servlet itself
52
 *     (which may support multiple servlet instances if the servlet itself
53
 *     implements SingleThreadModel).
53
 *     implements SingleThreadModel).
54
 * </ul>
54
 * </ul>
55
 * A given deployment of Catalina need not include Containers at all of the
55
 * A given deployment of Catalina need not include Containers at all of the
56
 * levels described above.  For example, an administration application
56
 * levels described above.  For example, an administration application
57
 * embedded within a network device (such as a router) might only contain
57
 * embedded within a network device (such as a router) might only contain
58
 * a single Context and a few Wrappers, or even a single Wrapper if the
58
 * a single Context and a few Wrappers, or even a single Wrapper if the
59
 * application is relatively small.  Therefore, Container implementations
59
 * application is relatively small.  Therefore, Container implementations
60
 * need to be designed so that they will operate correctly in the absence
60
 * need to be designed so that they will operate correctly in the absence
61
 * of parent Containers in a given deployment.
61
 * of parent Containers in a given deployment.
62
 * <p>
62
 * <p>
63
 * A Container may also be associated with a number of support components
63
 * A Container may also be associated with a number of support components
64
 * that provide functionality which might be shared (by attaching it to a
64
 * that provide functionality which might be shared (by attaching it to a
65
 * parent Container) or individually customized.  The following support
65
 * parent Container) or individually customized.  The following support
66
 * components are currently recognized:
66
 * components are currently recognized:
67
 * <ul>
67
 * <ul>
68
 * <li><b>Loader</b> - Class loader to use for integrating new Java classes
68
 * <li><b>Loader</b> - Class loader to use for integrating new Java classes
69
 *     for this Container into the JVM in which Catalina is running.
69
 *     for this Container into the JVM in which Catalina is running.
70
 * <li><b>Logger</b> - Implementation of the <code>log()</code> method
70
 * <li><b>Logger</b> - Implementation of the <code>log()</code> method
71
 *     signatures of the <code>ServletContext</code> interface.
71
 *     signatures of the <code>ServletContext</code> interface.
72
 * <li><b>Manager</b> - Manager for the pool of Sessions associated with
72
 * <li><b>Manager</b> - Manager for the pool of Sessions associated with
73
 *     this Container.
73
 *     this Container.
74
 * <li><b>Realm</b> - Read-only interface to a security domain, for
74
 * <li><b>Realm</b> - Read-only interface to a security domain, for
75
 *     authenticating user identities and their corresponding roles.
75
 *     authenticating user identities and their corresponding roles.
76
 * <li><b>Resources</b> - JNDI directory context enabling access to static
76
 * <li><b>Resources</b> - JNDI directory context enabling access to static
77
 *     resources, enabling custom linkages to existing server components when
77
 *     resources, enabling custom linkages to existing server components when
78
 *     Catalina is embedded in a larger server.
78
 *     Catalina is embedded in a larger server.
79
 * </ul>
79
 * </ul>
80
 *
80
 *
81
 * @author Craig R. McClanahan
81
 * @author Craig R. McClanahan
82
 * @author Remy Maucherat
82
 * @author Remy Maucherat
83
 * @version $Id$
83
 * @version $Id$
84
 */
84
 */
85
85
86
public interface Container extends Lifecycle {
86
public interface Container extends Lifecycle {
87
87
88
88
89
    // ----------------------------------------------------- Manifest Constants
89
    // ----------------------------------------------------- Manifest Constants
90
90
91
91
92
    /**
92
    /**
93
     * The ContainerEvent event type sent when a child container is added
93
     * The ContainerEvent event type sent when a child container is added
94
     * by <code>addChild()</code>.
94
     * by <code>addChild()</code>.
95
     */
95
     */
96
    public static final String ADD_CHILD_EVENT = "addChild";
96
    public static final String ADD_CHILD_EVENT = "addChild";
97
97
98
98
99
    /**
99
    /**
100
     * The ContainerEvent event type sent when a Mapper is added
100
     * The ContainerEvent event type sent when a Mapper is added
101
     * by <code>addMapper()</code>.
101
     * by <code>addMapper()</code>.
102
     */
102
     */
103
    public static final String ADD_MAPPER_EVENT = "addMapper";
103
    public static final String ADD_MAPPER_EVENT = "addMapper";
104
104
105
105
106
    /**
106
    /**
107
     * The ContainerEvent event type sent when a valve is added
107
     * The ContainerEvent event type sent when a valve is added
108
     * by <code>addValve()</code>, if this Container supports pipelines.
108
     * by <code>addValve()</code>, if this Container supports pipelines.
109
     */
109
     */
110
    public static final String ADD_VALVE_EVENT = "addValve";
110
    public static final String ADD_VALVE_EVENT = "addValve";
111
111
112
112
113
    /**
113
    /**
114
     * The ContainerEvent event type sent when a child container is removed
114
     * The ContainerEvent event type sent when a child container is removed
115
     * by <code>removeChild()</code>.
115
     * by <code>removeChild()</code>.
116
     */
116
     */
117
    public static final String REMOVE_CHILD_EVENT = "removeChild";
117
    public static final String REMOVE_CHILD_EVENT = "removeChild";
118
118
119
119
120
    /**
120
    /**
121
     * The ContainerEvent event type sent when a Mapper is removed
121
     * The ContainerEvent event type sent when a Mapper is removed
122
     * by <code>removeMapper()</code>.
122
     * by <code>removeMapper()</code>.
123
     */
123
     */
124
    public static final String REMOVE_MAPPER_EVENT = "removeMapper";
124
    public static final String REMOVE_MAPPER_EVENT = "removeMapper";
125
125
126
126
127
    /**
127
    /**
128
     * The ContainerEvent event type sent when a valve is removed
128
     * The ContainerEvent event type sent when a valve is removed
129
     * by <code>removeValve()</code>, if this Container supports pipelines.
129
     * by <code>removeValve()</code>, if this Container supports pipelines.
130
     */
130
     */
131
    public static final String REMOVE_VALVE_EVENT = "removeValve";
131
    public static final String REMOVE_VALVE_EVENT = "removeValve";
132
132
133
133
134
    // ------------------------------------------------------------- Properties
134
    // ------------------------------------------------------------- Properties
135
135
136
136
137
    /**
137
    /**
138
     * Return descriptive information about this Container implementation and
138
     * Return descriptive information about this Container implementation and
139
     * the corresponding version number, in the format
139
     * the corresponding version number, in the format
140
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
140
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
141
     */
141
     */
142
    public String getInfo();
142
    public String getInfo();
143
143
144
144
145
    /**
145
    /**
146
     * Return the Loader with which this Container is associated.  If there is
146
     * Return the Loader with which this Container is associated.  If there is
147
     * no associated Loader, return the Loader associated with our parent
147
     * no associated Loader, return the Loader associated with our parent
148
     * Container (if any); otherwise, return <code>null</code>.
148
     * Container (if any); otherwise, return <code>null</code>.
149
     */
149
     */
150
    public Loader getLoader();
150
    public Loader getLoader();
151
151
152
152
153
    /**
153
    /**
154
     * Set the Loader with which this Container is associated.
154
     * Set the Loader with which this Container is associated.
155
     *
155
     *
156
     * @param loader The newly associated loader
156
     * @param loader The newly associated loader
157
     */
157
     */
158
    public void setLoader(Loader loader);
158
    public void setLoader(Loader loader);
159
159
160
160
161
    /**
161
    /**
162
     * Return the Logger with which this Container is associated.  If there is
162
     * Return the Logger with which this Container is associated.  If there is
163
     * no associated Logger, return the Logger associated with our parent
163
     * no associated Logger, return the Logger associated with our parent
164
     * Container (if any); otherwise return <code>null</code>.
164
     * Container (if any); otherwise return <code>null</code>.
165
     */
165
     */
166
    public Log getLogger();
166
    public Log getLogger();
167
167
168
168
169
    /**
169
    /**
170
     * Return the Manager with which this Container is associated.  If there is
170
     * Return the Manager with which this Container is associated.  If there is
171
     * no associated Manager, return the Manager associated with our parent
171
     * no associated Manager, return the Manager associated with our parent
172
     * Container (if any); otherwise return <code>null</code>.
172
     * Container (if any); otherwise return <code>null</code>.
173
     */
173
     */
174
    public Manager getManager();
174
    public Manager getManager();
175
175
176
176
177
    /**
177
    /**
178
     * Set the Manager with which this Container is associated.
178
     * Set the Manager with which this Container is associated.
179
     *
179
     *
180
     * @param manager The newly associated Manager
180
     * @param manager The newly associated Manager
181
     */
181
     */
182
    public void setManager(Manager manager);
182
    public void setManager(Manager manager);
183
183
184
184
185
    /**
185
    /**
186
     * Return an object which may be utilized for mapping to this component.
186
     * Return an object which may be utilized for mapping to this component.
187
     */
187
     */
188
    public Object getMappingObject();
188
    public Object getMappingObject();
189
189
190
    
190
    
191
    /**
191
    /**
192
     * Return the JMX name associated with this container.
192
     * Return the JMX name associated with this container.
193
     */
193
     */
194
    public ObjectName getObjectName();    
194
    public ObjectName getObjectName();    
195
195
196
    /**
196
    /**
197
     * Return the Pipeline object that manages the Valves associated with
197
     * Return the Pipeline object that manages the Valves associated with
198
     * this Container.
198
     * this Container.
199
     */
199
     */
200
    public Pipeline getPipeline();
200
    public Pipeline getPipeline();
201
201
202
202
203
    /**
203
    /**
204
     * Return the Cluster with which this Container is associated.  If there is
204
     * Return the Cluster with which this Container is associated.  If there is
205
     * no associated Cluster, return the Cluster associated with our parent
205
     * no associated Cluster, return the Cluster associated with our parent
206
     * Container (if any); otherwise return <code>null</code>.
206
     * Container (if any); otherwise return <code>null</code>.
207
     */
207
     */
208
    public Cluster getCluster();
208
    public Cluster getCluster();
209
209
210
210
211
    /**
211
    /**
212
     * Set the Cluster with which this Container is associated.
212
     * Set the Cluster with which this Container is associated.
213
     *
213
     *
214
     * @param cluster the Cluster with which this Container is associated.
214
     * @param cluster the Cluster with which this Container is associated.
215
     */
215
     */
216
    public void setCluster(Cluster cluster);
216
    public void setCluster(Cluster cluster);
217
217
218
218
219
    /**
219
    /**
220
     * Get the delay between the invocation of the backgroundProcess method on
220
     * Get the delay between the invocation of the backgroundProcess method on
221
     * this container and its children. Child containers will not be invoked
221
     * this container and its children. Child containers will not be invoked
222
     * if their delay value is not negative (which would mean they are using 
222
     * if their delay value is not negative (which would mean they are using 
223
     * their own thread). Setting this to a positive value will cause 
223
     * their own thread). Setting this to a positive value will cause 
224
     * a thread to be spawn. After waiting the specified amount of time, 
224
     * a thread to be spawn. After waiting the specified amount of time, 
225
     * the thread will invoke the executePeriodic method on this container 
225
     * the thread will invoke the executePeriodic method on this container 
226
     * and all its children.
226
     * and all its children.
227
     */
227
     */
228
    public int getBackgroundProcessorDelay();
228
    public int getBackgroundProcessorDelay();
229
229
230
230
231
    /**
231
    /**
232
     * Set the delay between the invocation of the execute method on this
232
     * Set the delay between the invocation of the execute method on this
233
     * container and its children.
233
     * container and its children.
234
     * 
234
     * 
235
     * @param delay The delay in seconds between the invocation of 
235
     * @param delay The delay in seconds between the invocation of 
236
     *              backgroundProcess methods
236
     *              backgroundProcess methods
237
     */
237
     */
238
    public void setBackgroundProcessorDelay(int delay);
238
    public void setBackgroundProcessorDelay(int delay);
239
239
240
240
241
    /**
241
    /**
242
     * Return a name string (suitable for use by humans) that describes this
242
     * Return a name string (suitable for use by humans) that describes this
243
     * Container.  Within the set of child containers belonging to a particular
243
     * Container.  Within the set of child containers belonging to a particular
244
     * parent, Container names must be unique.
244
     * parent, Container names must be unique.
245
     */
245
     */
246
    public String getName();
246
    public String getName();
247
247
248
248
249
    /**
249
    /**
250
     * Set a name string (suitable for use by humans) that describes this
250
     * Set a name string (suitable for use by humans) that describes this
251
     * Container.  Within the set of child containers belonging to a particular
251
     * Container.  Within the set of child containers belonging to a particular
252
     * parent, Container names must be unique.
252
     * parent, Container names must be unique.
253
     *
253
     *
254
     * @param name New name of this container
254
     * @param name New name of this container
255
     *
255
     *
256
     * @exception IllegalStateException if this Container has already been
256
     * @exception IllegalStateException if this Container has already been
257
     *  added to the children of a parent Container (after which the name
257
     *  added to the children of a parent Container (after which the name
258
     *  may not be changed)
258
     *  may not be changed)
259
     */
259
     */
260
    public void setName(String name);
260
    public void setName(String name);
261
261
262
262
263
    /**
263
    /**
264
     * Return the Container for which this Container is a child, if there is
264
     * Return the Container for which this Container is a child, if there is
265
     * one.  If there is no defined parent, return <code>null</code>.
265
     * one.  If there is no defined parent, return <code>null</code>.
266
     */
266
     */
267
    public Container getParent();
267
    public Container getParent();
268
268
269
269
270
    /**
270
    /**
271
     * Set the parent Container to which this Container is being added as a
271
     * Set the parent Container to which this Container is being added as a
272
     * child.  This Container may refuse to become attached to the specified
272
     * child.  This Container may refuse to become attached to the specified
273
     * Container by throwing an exception.
273
     * Container by throwing an exception.
274
     *
274
     *
275
     * @param container Container to which this Container is being added
275
     * @param container Container to which this Container is being added
276
     *  as a child
276
     *  as a child
277
     *
277
     *
278
     * @exception IllegalArgumentException if this Container refuses to become
278
     * @exception IllegalArgumentException if this Container refuses to become
279
     *  attached to the specified Container
279
     *  attached to the specified Container
280
     */
280
     */
281
    public void setParent(Container container);
281
    public void setParent(Container container);
282
282
283
283
284
    /**
284
    /**
285
     * Return the parent class loader for this component. If not set, return
285
     * Return the parent class loader for this component. If not set, return
286
     * {@link #getParent()} {@link #getParentClassLoader()}. If no parent has
286
     * {@link #getParent()} {@link #getParentClassLoader()}. If no parent has
287
     * been set, return the system class loader.
287
     * been set, return the system class loader.
288
     */
288
     */
289
    public ClassLoader getParentClassLoader();
289
    public ClassLoader getParentClassLoader();
290
290
291
291
292
    /**
292
    /**
293
     * Set the parent class loader for this component. For {@link Context}s
293
     * Set the parent class loader for this component. For {@link Context}s
294
     * this call is meaningful only <strong>before</strong> a Loader has
294
     * this call is meaningful only <strong>before</strong> a Loader has
295
     * been configured, and the specified value (if non-null) should be
295
     * been configured, and the specified value (if non-null) should be
296
     * passed as an argument to the class loader constructor.
296
     * passed as an argument to the class loader constructor.
297
     *
297
     *
298
     * @param parent The new parent class loader
298
     * @param parent The new parent class loader
299
     */
299
     */
300
    public void setParentClassLoader(ClassLoader parent);
300
    public void setParentClassLoader(ClassLoader parent);
301
301
302
302
303
    /**
303
    /**
304
     * Return the Realm with which this Container is associated.  If there is
304
     * Return the Realm with which this Container is associated.  If there is
305
     * no associated Realm, return the Realm associated with our parent
305
     * no associated Realm, return the Realm associated with our parent
306
     * Container (if any); otherwise return <code>null</code>.
306
     * Container (if any); otherwise return <code>null</code>.
307
     */
307
     */
308
    public Realm getRealm();
308
    public Realm getRealm();
309
309
310
310
311
    /**
311
    /**
312
     * Set the Realm with which this Container is associated.
312
     * Set the Realm with which this Container is associated.
313
     *
313
     *
314
     * @param realm The newly associated Realm
314
     * @param realm The newly associated Realm
315
     */
315
     */
316
    public void setRealm(Realm realm);
316
    public void setRealm(Realm realm);
317
317
318
318
319
    /**
319
    /**
320
     * Return the Resources with which this Container is associated.  If there
320
     * Return the Resources with which this Container is associated.  If there
321
     * is no associated Resources object, return the Resources associated with
321
     * is no associated Resources object, return the Resources associated with
322
     * our parent Container (if any); otherwise return <code>null</code>.
322
     * our parent Container (if any); otherwise return <code>null</code>.
323
     */
323
     */
324
    public DirContext getResources();
324
    public DirContext getResources();
325
325
326
326
327
    /**
327
    /**
328
     * Set the Resources object with which this Container is associated.
328
     * Set the Resources object with which this Container is associated.
329
     *
329
     *
330
     * @param resources The newly associated Resources
330
     * @param resources The newly associated Resources
331
     */
331
     */
332
    public void setResources(DirContext resources);
332
    public void setResources(DirContext resources);
333
333
334
334
335
    // --------------------------------------------------------- Public Methods
335
    // --------------------------------------------------------- Public Methods
336
336
337
337
338
    /**
338
    /**
339
     * Execute a periodic task, such as reloading, etc. This method will be
339
     * Execute a periodic task, such as reloading, etc. This method will be
340
     * invoked inside the classloading context of this container. Unexpected
340
     * invoked inside the classloading context of this container. Unexpected
341
     * throwables will be caught and logged.
341
     * throwables will be caught and logged.
342
     */
342
     */
343
    public void backgroundProcess();
343
    public void backgroundProcess();
344
344
345
345
346
    /**
346
    /**
347
     * Add a new child Container to those associated with this Container,
347
     * Add a new child Container to those associated with this Container,
348
     * if supported.  Prior to adding this Container to the set of children,
348
     * if supported.  Prior to adding this Container to the set of children,
349
     * the child's <code>setParent()</code> method must be called, with this
349
     * the child's <code>setParent()</code> method must be called, with this
350
     * Container as an argument.  This method may thrown an
350
     * Container as an argument.  This method may thrown an
351
     * <code>IllegalArgumentException</code> if this Container chooses not
351
     * <code>IllegalArgumentException</code> if this Container chooses not
352
     * to be attached to the specified Container, in which case it is not added
352
     * to be attached to the specified Container, in which case it is not added
353
     *
353
     *
354
     * @param child New child Container to be added
354
     * @param child New child Container to be added
355
     *
355
     *
356
     * @exception IllegalArgumentException if this exception is thrown by
356
     * @exception IllegalArgumentException if this exception is thrown by
357
     *  the <code>setParent()</code> method of the child Container
357
     *  the <code>setParent()</code> method of the child Container
358
     * @exception IllegalArgumentException if the new child does not have
358
     * @exception IllegalArgumentException if the new child does not have
359
     *  a name unique from that of existing children of this Container
359
     *  a name unique from that of existing children of this Container
360
     * @exception IllegalStateException if this Container does not support
360
     * @exception IllegalStateException if this Container does not support
361
     *  child Containers
361
     *  child Containers
362
     */
362
     */
363
    public void addChild(Container child);
363
    public void addChild(Container child);
364
364
365
365
366
    /**
366
    /**
367
     * Add a container event listener to this component.
367
     * Add a container event listener to this component.
368
     *
368
     *
369
     * @param listener The listener to add
369
     * @param listener The listener to add
370
     */
370
     */
371
    public void addContainerListener(ContainerListener listener);
371
    public void addContainerListener(ContainerListener listener);
372
372
373
373
374
    /**
374
    /**
375
     * Add a property change listener to this component.
375
     * Add a property change listener to this component.
376
     *
376
     *
377
     * @param listener The listener to add
377
     * @param listener The listener to add
378
     */
378
     */
379
    public void addPropertyChangeListener(PropertyChangeListener listener);
379
    public void addPropertyChangeListener(PropertyChangeListener listener);
380
380
381
381
382
    /**
382
    /**
383
     * Return the child Container, associated with this Container, with
383
     * Return the child Container, associated with this Container, with
384
     * the specified name (if any); otherwise, return <code>null</code>
384
     * the specified name (if any); otherwise, return <code>null</code>
385
     *
385
     *
386
     * @param name Name of the child Container to be retrieved
386
     * @param name Name of the child Container to be retrieved
387
     */
387
     */
388
    public Container findChild(String name);
388
    public Container findChild(String name);
389
389
390
390
391
    /**
391
    /**
392
     * Return the set of children Containers associated with this Container.
392
     * Return the set of children Containers associated with this Container.
393
     * If this Container has no children, a zero-length array is returned.
393
     * If this Container has no children, a zero-length array is returned.
394
     */
394
     */
395
    public Container[] findChildren();
395
    public Container[] findChildren();
396
396
397
397
398
    /**
398
    /**
399
     * Return the set of container listeners associated with this Container.
399
     * Return the set of container listeners associated with this Container.
400
     * If this Container has no registered container listeners, a zero-length
400
     * If this Container has no registered container listeners, a zero-length
401
     * array is returned.
401
     * array is returned.
402
     */
402
     */
403
    public ContainerListener[] findContainerListeners();
403
    public ContainerListener[] findContainerListeners();
404
404
405
405
406
    /**
406
    /**
407
     * Process the specified Request, and generate the corresponding Response,
407
     * Process the specified Request, and generate the corresponding Response,
408
     * according to the design of this particular Container.
408
     * according to the design of this particular Container.
409
     *
409
     *
410
     * @param request Request to be processed
410
     * @param request Request to be processed
411
     * @param response Response to be produced
411
     * @param response Response to be produced
412
     *
412
     *
413
     * @exception IOException if an input/output error occurred while
413
     * @exception IOException if an input/output error occurred while
414
     *  processing
414
     *  processing
415
     * @exception ServletException if a ServletException was thrown
415
     * @exception ServletException if a ServletException was thrown
416
     *  while processing this request
416
     *  while processing this request
417
     */
417
     */
418
    public void invoke(Request request, Response response)
418
    public void invoke(Request request, Response response)
419
        throws IOException, ServletException;
419
        throws IOException, ServletException;
420
420
421
421
422
    /**
422
    /**
423
     * Remove an existing child Container from association with this parent
423
     * Remove an existing child Container from association with this parent
424
     * Container.
424
     * Container.
425
     *
425
     *
426
     * @param child Existing child Container to be removed
426
     * @param child Existing child Container to be removed
427
     */
427
     */
428
    public void removeChild(Container child);
428
    public void removeChild(Container child);
429
429
430
430
431
    /**
431
    /**
432
     * Remove a container event listener from this component.
432
     * Remove a container event listener from this component.
433
     *
433
     *
434
     * @param listener The listener to remove
434
     * @param listener The listener to remove
435
     */
435
     */
436
    public void removeContainerListener(ContainerListener listener);
436
    public void removeContainerListener(ContainerListener listener);
437
437
438
438
439
    /**
439
    /**
440
     * Remove a property change listener from this component.
440
     * Remove a property change listener from this component.
441
     *
441
     *
442
     * @param listener The listener to remove
442
     * @param listener The listener to remove
443
     */
443
     */
444
    public void removePropertyChangeListener(PropertyChangeListener listener);
444
    public void removePropertyChangeListener(PropertyChangeListener listener);
445
445
446
446
447
    /**
447
    /**
448
     * Notify all container event listeners that a particular event has
448
     * Notify all container event listeners that a particular event has
449
     * occurred for this Container.  The default implementation performs
449
     * occurred for this Container.  The default implementation performs
450
     * this notification synchronously using the calling thread.
450
     * this notification synchronously using the calling thread.
451
     *
451
     *
452
     * @param type Event type
452
     * @param type Event type
453
     * @param data Event data
453
     * @param data Event data
454
     */
454
     */
455
    public void fireContainerEvent(String type, Object data);
455
    public void fireContainerEvent(String type, Object data);
456
    
456
    
457
    
457
    
458
    /**
458
    /**
459
     * Log a request/response that was destined for this container but has been
459
     * Log a request/response that was destined for this container but has been
460
     * handled earlier in the processing chain so that the request/response
460
     * handled earlier in the processing chain so that the request/response
461
     * still appears in the correct access logs.
461
     * still appears in the correct access logs.
462
     * @param request       Request (associated with the response) to log
462
     * @param request       Request (associated with the response) to log
463
     * @param response      Response (associated with the request) to log
463
     * @param response      Response (associated with the request) to log
464
     * @param time          Time taken to process the request/response in
464
     * @param time          Time taken to process the request/response in
465
     *                      milliseconds (use 0 if not known) 
465
     *                      milliseconds (use 0 if not known) 
466
     * @param   useDefault  Flag that indicates that the request/response should
466
     * @param   useDefault  Flag that indicates that the request/response should
467
     *                      be logged in the engine's default access log
467
     *                      be logged in the engine's default access log
468
     */
468
     */
469
    public void logAccess(Request request, Response response, long time,
469
    public void logAccess(Request request, Response response, long time,
470
            boolean useDefault);
470
            boolean useDefault);
471
    
471
    
472
    
472
    
473
    /**
473
    /**
474
     * Identify the AccessLog to use to log a request/response that was destined
474
     * Identify the AccessLog to use to log a request/response that was destined
475
     * for this container but was handled earlier in the processing chain so
475
     * for this container but was handled earlier in the processing chain so
476
     * that the request/response still appears in the correct access logs.
476
     * that the request/response still appears in the correct access logs.
477
     */
477
     */
478
    public AccessLog getAccessLog();
478
    public AccessLog getAccessLog();
479
}
479
    
480
    
481
    /**
482
     * Returns the number of threads available for starting and stopping any
483
     * children associated with this container. This allows start/stop calls to
484
     * children to be processed in parallel.
485
     */
486
    public int getStartStopThreads();
487
488
489
    /**
490
     * Sets the number of threads available for starting and stopping any
491
     * children associated with this container. This allows start/stop calls to
492
     * children to be processed in parallel.
493
     * @param   startStopThreads    The new number of threads to be used
494
     */
495
    public void setStartStopThreads(int startStopThreads);
496
}
(-)a/java/org/apache/catalina/Host.java (-220 / +228 lines)
Lines 1-220 Link Here
1
/*
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
package org.apache.catalina;
17
package org.apache.catalina;
18
18
19
import java.io.File;
19
import java.io.File;
20
import java.util.regex.Pattern;
20
import java.util.concurrent.ExecutorService;
21
21
import java.util.regex.Pattern;
22
22
23
/**
23
24
 * A <b>Host</b> is a Container that represents a virtual host in the
24
/**
25
 * Catalina servlet engine.  It is useful in the following types of scenarios:
25
 * A <b>Host</b> is a Container that represents a virtual host in the
26
 * <ul>
26
 * Catalina servlet engine.  It is useful in the following types of scenarios:
27
 * <li>You wish to use Interceptors that see every single request processed
27
 * <ul>
28
 *     by this particular virtual host.
28
 * <li>You wish to use Interceptors that see every single request processed
29
 * <li>You wish to run Catalina in with a standalone HTTP connector, but still
29
 *     by this particular virtual host.
30
 *     want support for multiple virtual hosts.
30
 * <li>You wish to run Catalina in with a standalone HTTP connector, but still
31
 * </ul>
31
 *     want support for multiple virtual hosts.
32
 * In general, you would not use a Host when deploying Catalina connected
32
 * </ul>
33
 * to a web server (such as Apache), because the Connector will have
33
 * In general, you would not use a Host when deploying Catalina connected
34
 * utilized the web server's facilities to determine which Context (or
34
 * to a web server (such as Apache), because the Connector will have
35
 * perhaps even which Wrapper) should be utilized to process this request.
35
 * utilized the web server's facilities to determine which Context (or
36
 * <p>
36
 * perhaps even which Wrapper) should be utilized to process this request.
37
 * The parent Container attached to a Host is generally an Engine, but may
37
 * <p>
38
 * be some other implementation, or may be omitted if it is not necessary.
38
 * The parent Container attached to a Host is generally an Engine, but may
39
 * <p>
39
 * be some other implementation, or may be omitted if it is not necessary.
40
 * The child containers attached to a Host are generally implementations
40
 * <p>
41
 * of Context (representing an individual servlet context).
41
 * The child containers attached to a Host are generally implementations
42
 *
42
 * of Context (representing an individual servlet context).
43
 * @author Craig R. McClanahan
43
 *
44
 * @version $Id$
44
 * @author Craig R. McClanahan
45
 */
45
 * @version $Id$
46
46
 */
47
public interface Host extends Container {
47
48
48
public interface Host extends Container {
49
49
50
    // ----------------------------------------------------- Manifest Constants
50
51
51
    // ----------------------------------------------------- Manifest Constants
52
52
53
    /**
53
54
     * The ContainerEvent event type sent when a new alias is added
54
    /**
55
     * by <code>addAlias()</code>.
55
     * The ContainerEvent event type sent when a new alias is added
56
     */
56
     * by <code>addAlias()</code>.
57
    public static final String ADD_ALIAS_EVENT = "addAlias";
57
     */
58
58
    public static final String ADD_ALIAS_EVENT = "addAlias";
59
59
60
    /**
60
61
     * The ContainerEvent event type sent when an old alias is removed
61
    /**
62
     * by <code>removeAlias()</code>.
62
     * The ContainerEvent event type sent when an old alias is removed
63
     */
63
     * by <code>removeAlias()</code>.
64
    public static final String REMOVE_ALIAS_EVENT = "removeAlias";
64
     */
65
65
    public static final String REMOVE_ALIAS_EVENT = "removeAlias";
66
66
67
    // ------------------------------------------------------------- Properties
67
68
68
    // ------------------------------------------------------------- Properties
69
69
70
    /**
70
71
     * Return the XML root for this Host.  This can be an absolute
71
    /**
72
     * pathname, a relative pathname, or a URL.
72
     * Return the XML root for this Host.  This can be an absolute
73
     * If null, defaults to
73
     * pathname, a relative pathname, or a URL.
74
     * ${catalina.base}/conf/&lt;engine name&gt;/&lt;host name&gt; directory
74
     * If null, defaults to
75
     */
75
     * ${catalina.base}/conf/&lt;engine name&gt;/&lt;host name&gt; directory
76
    public String getXmlBase();
76
     */
77
    
77
    public String getXmlBase();
78
    /**
78
    
79
     * Set the Xml root for this Host.  This can be an absolute
79
    /**
80
     * pathname, a relative pathname, or a URL.
80
     * Set the Xml root for this Host.  This can be an absolute
81
     * If null, defaults to
81
     * pathname, a relative pathname, or a URL.
82
     * ${catalina.base}/conf/&lt;engine name&gt;/&lt;host name&gt; directory
82
     * If null, defaults to
83
     * @param xmlBase The new XML root
83
     * ${catalina.base}/conf/&lt;engine name&gt;/&lt;host name&gt; directory
84
     */
84
     * @param xmlBase The new XML root
85
    public void setXmlBase(String xmlBase);
85
     */
86
86
    public void setXmlBase(String xmlBase);
87
    /**
87
88
     * Return the application root for this Host.  This can be an absolute
88
    /**
89
     * pathname, a relative pathname, or a URL.
89
     * Return the application root for this Host.  This can be an absolute
90
     */
90
     * pathname, a relative pathname, or a URL.
91
    public String getAppBase();
91
     */
92
92
    public String getAppBase();
93
93
94
    /**
94
95
     * Return an absolute {@link File} for the appBase of this Host. The file
95
    /**
96
     * will be canonical if possible. There is no guarantee that that the
96
     * Return an absolute {@link File} for the appBase of this Host. The file
97
     * appBase exists.
97
     * will be canonical if possible. There is no guarantee that that the
98
     */
98
     * appBase exists.
99
    public File getAppBaseFile();
99
     */
100
100
    public File getAppBaseFile();
101
101
102
    /**
102
103
     * Set the application root for this Host.  This can be an absolute
103
    /**
104
     * pathname, a relative pathname, or a URL.
104
     * Set the application root for this Host.  This can be an absolute
105
     *
105
     * pathname, a relative pathname, or a URL.
106
     * @param appBase The new application root
106
     *
107
     */
107
     * @param appBase The new application root
108
    public void setAppBase(String appBase);
108
     */
109
109
    public void setAppBase(String appBase);
110
110
111
    /**
111
112
     * Return the value of the auto deploy flag.  If true, it indicates that 
112
    /**
113
     * this host's child webapps should be discovered and automatically 
113
     * Return the value of the auto deploy flag.  If true, it indicates that 
114
     * deployed dynamically.
114
     * this host's child webapps should be discovered and automatically 
115
     */
115
     * deployed dynamically.
116
    public boolean getAutoDeploy();
116
     */
117
117
    public boolean getAutoDeploy();
118
118
119
    /**
119
120
     * Set the auto deploy flag value for this host.
120
    /**
121
     * 
121
     * Set the auto deploy flag value for this host.
122
     * @param autoDeploy The new auto deploy flag
122
     * 
123
     */
123
     * @param autoDeploy The new auto deploy flag
124
    public void setAutoDeploy(boolean autoDeploy);
124
     */
125
125
    public void setAutoDeploy(boolean autoDeploy);
126
126
127
    /**
127
128
     * Return the Java class name of the context configuration class
128
    /**
129
     * for new web applications.
129
     * Return the Java class name of the context configuration class
130
     */
130
     * for new web applications.
131
    public String getConfigClass();
131
     */
132
132
    public String getConfigClass();
133
    
133
134
    /**
134
    
135
     * Set the Java class name of the context configuration class
135
    /**
136
     * for new web applications.
136
     * Set the Java class name of the context configuration class
137
     *
137
     * for new web applications.
138
     * @param configClass The new context configuration class
138
     *
139
     */
139
     * @param configClass The new context configuration class
140
    public void setConfigClass(String configClass);
140
     */
141
141
    public void setConfigClass(String configClass);
142
        
142
143
    /**
143
        
144
     * Return the value of the deploy on startup flag.  If true, it indicates 
144
    /**
145
     * that this host's child webapps should be discovered and automatically 
145
     * Return the value of the deploy on startup flag.  If true, it indicates 
146
     * deployed.
146
     * that this host's child webapps should be discovered and automatically 
147
     */
147
     * deployed.
148
    public boolean getDeployOnStartup();
148
     */
149
149
    public boolean getDeployOnStartup();
150
150
151
    /**
151
152
     * Set the deploy on startup flag value for this host.
152
    /**
153
     * 
153
     * Set the deploy on startup flag value for this host.
154
     * @param deployOnStartup The new deploy on startup flag
154
     * 
155
     */
155
     * @param deployOnStartup The new deploy on startup flag
156
    public void setDeployOnStartup(boolean deployOnStartup);
156
     */
157
157
    public void setDeployOnStartup(boolean deployOnStartup);
158
158
159
    /**
159
160
     * Return the regular expression that defines the files and directories in
160
    /**
161
     * the host's appBase that will be ignored by the automatic deployment
161
     * Return the regular expression that defines the files and directories in
162
     * process.
162
     * the host's appBase that will be ignored by the automatic deployment
163
     */
163
     * process.
164
    public String getDeployIgnore();
164
     */
165
165
    public String getDeployIgnore();
166
166
167
    /**
167
168
     * Return the compiled regular expression that defines the files and
168
    /**
169
     * directories in the host's appBase that will be ignored by the automatic
169
     * Return the compiled regular expression that defines the files and
170
     * deployment process.
170
     * directories in the host's appBase that will be ignored by the automatic
171
     */
171
     * deployment process.
172
    public Pattern getDeployIgnorePattern();
172
     */
173
173
    public Pattern getDeployIgnorePattern();
174
174
175
    /**
175
176
     * Set the regular expression that defines the files and directories in
176
    /**
177
     * the host's appBase that will be ignored by the automatic deployment
177
     * Set the regular expression that defines the files and directories in
178
     * process.
178
     * the host's appBase that will be ignored by the automatic deployment
179
     */
179
     * process.
180
    public void setDeployIgnore(String deployIgnore);
180
     */
181
181
    public void setDeployIgnore(String deployIgnore);
182
182
183
    // --------------------------------------------------------- Public Methods
183
184
184
    /**
185
185
     * Return the executor that is used for starting and stopping contexts. This
186
    /**
186
     * is primarily for use by components deploying contexts that want to do
187
     * Add an alias name that should be mapped to this same Host.
187
     * this in a multi-threaded manner.
188
     *
188
     */
189
     * @param alias The alias to be added
189
    public ExecutorService getStartStopExecutor();
190
     */
190
    
191
    public void addAlias(String alias);
191
    
192
192
    // --------------------------------------------------------- Public Methods
193
193
194
    /**
194
    /**
195
     * Return the set of alias names for this Host.  If none are defined,
195
     * Add an alias name that should be mapped to this same Host.
196
     * a zero length array is returned.
196
     *
197
     */
197
     * @param alias The alias to be added
198
    public String[] findAliases();
198
     */
199
199
    public void addAlias(String alias);
200
200
201
    /**
201
202
     * Remove the specified alias name from the aliases for this Host.
202
    /**
203
     *
203
     * Return the set of alias names for this Host.  If none are defined,
204
     * @param alias Alias name to be removed
204
     * a zero length array is returned.
205
     */
205
     */
206
    public void removeAlias(String alias);
206
    public String[] findAliases();
207
207
208
    /**
208
209
     * Returns true if the Host will attempt to create directories for appBase and xmlBase
209
    /**
210
     * unless they already exist.
210
     * Remove the specified alias name from the aliases for this Host.
211
     * @return true if the Host will attempt to create directories
211
     *
212
     */
212
     * @param alias Alias name to be removed
213
    public boolean getCreateDirs();
213
     */
214
    /**
214
    public void removeAlias(String alias);
215
     * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup
215
216
     * @param createDirs
216
    /**
217
     */
217
     * Returns true if the Host will attempt to create directories for appBase and xmlBase
218
    public void setCreateDirs(boolean createDirs);
218
     * unless they already exist.
219
219
     * @return true if the Host will attempt to create directories
220
}
220
     */
221
    public boolean getCreateDirs();
222
    /**
223
     * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup
224
     * @param createDirs
225
     */
226
    public void setCreateDirs(boolean createDirs);
227
228
}
(-)a/java/org/apache/catalina/core/ContainerBase.java (-1415 / +1546 lines)
Lines 1-1415 Link Here
1
/*
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
package org.apache.catalina.core;
17
package org.apache.catalina.core;
18
18
19
19
20
import java.beans.PropertyChangeListener;
20
import java.beans.PropertyChangeListener;
21
import java.beans.PropertyChangeSupport;
21
import java.beans.PropertyChangeSupport;
22
import java.io.IOException;
22
import java.io.IOException;
23
import java.security.AccessController;
23
import java.security.AccessController;
24
import java.security.PrivilegedAction;
24
import java.security.PrivilegedAction;
25
import java.util.ArrayList;
25
import java.util.ArrayList;
26
import java.util.HashMap;
26
import java.util.HashMap;
27
import java.util.Hashtable;
27
import java.util.Hashtable;
28
import java.util.Iterator;
28
import java.util.Iterator;
29
29
import java.util.List;
30
import javax.management.ObjectName;
30
import java.util.concurrent.BlockingQueue;
31
import javax.naming.directory.DirContext;
31
import java.util.concurrent.Callable;
32
import javax.servlet.ServletException;
32
import java.util.concurrent.Future;
33
33
import java.util.concurrent.LinkedBlockingQueue;
34
import org.apache.catalina.AccessLog;
34
import java.util.concurrent.ThreadPoolExecutor;
35
import org.apache.catalina.CatalinaFactory;
35
import java.util.concurrent.TimeUnit;
36
import org.apache.catalina.Cluster;
36
37
import org.apache.catalina.Container;
37
import javax.management.ObjectName;
38
import org.apache.catalina.ContainerEvent;
38
import javax.naming.directory.DirContext;
39
import org.apache.catalina.ContainerListener;
39
import javax.servlet.ServletException;
40
import org.apache.catalina.Globals;
40
41
import org.apache.catalina.Lifecycle;
41
import org.apache.catalina.AccessLog;
42
import org.apache.catalina.LifecycleException;
42
import org.apache.catalina.CatalinaFactory;
43
import org.apache.catalina.LifecycleState;
43
import org.apache.catalina.Cluster;
44
import org.apache.catalina.Loader;
44
import org.apache.catalina.Container;
45
import org.apache.catalina.Manager;
45
import org.apache.catalina.ContainerEvent;
46
import org.apache.catalina.Pipeline;
46
import org.apache.catalina.ContainerListener;
47
import org.apache.catalina.Realm;
47
import org.apache.catalina.Globals;
48
import org.apache.catalina.Valve;
48
import org.apache.catalina.Lifecycle;
49
import org.apache.catalina.connector.Request;
49
import org.apache.catalina.LifecycleException;
50
import org.apache.catalina.connector.Response;
50
import org.apache.catalina.LifecycleState;
51
import org.apache.catalina.mbeans.MBeanUtils;
51
import org.apache.catalina.Loader;
52
import org.apache.catalina.util.LifecycleMBeanBase;
52
import org.apache.catalina.Manager;
53
import org.apache.juli.logging.Log;
53
import org.apache.catalina.Pipeline;
54
import org.apache.juli.logging.LogFactory;
54
import org.apache.catalina.Realm;
55
import org.apache.naming.resources.ProxyDirContext;
55
import org.apache.catalina.Valve;
56
import org.apache.tomcat.util.ExceptionUtils;
56
import org.apache.catalina.connector.Request;
57
import org.apache.tomcat.util.res.StringManager;
57
import org.apache.catalina.connector.Response;
58
58
import org.apache.catalina.mbeans.MBeanUtils;
59
59
import org.apache.catalina.util.LifecycleMBeanBase;
60
/**
60
import org.apache.juli.logging.Log;
61
 * Abstract implementation of the <b>Container</b> interface, providing common
61
import org.apache.juli.logging.LogFactory;
62
 * functionality required by nearly every implementation.  Classes extending
62
import org.apache.naming.resources.ProxyDirContext;
63
 * this base class must implement <code>getInfo()</code>, and may implement
63
import org.apache.tomcat.util.ExceptionUtils;
64
 * a replacement for <code>invoke()</code>.
64
import org.apache.tomcat.util.res.StringManager;
65
 * <p>
65
66
 * All subclasses of this abstract base class will include support for a
66
67
 * Pipeline object that defines the processing to be performed for each request
67
/**
68
 * received by the <code>invoke()</code> method of this class, utilizing the
68
 * Abstract implementation of the <b>Container</b> interface, providing common
69
 * "Chain of Responsibility" design pattern.  A subclass should encapsulate its
69
 * functionality required by nearly every implementation.  Classes extending
70
 * own processing functionality as a <code>Valve</code>, and configure this
70
 * this base class must implement <code>getInfo()</code>, and may implement
71
 * Valve into the pipeline by calling <code>setBasic()</code>.
71
 * a replacement for <code>invoke()</code>.
72
 * <p>
72
 * <p>
73
 * This implementation fires property change events, per the JavaBeans design
73
 * All subclasses of this abstract base class will include support for a
74
 * pattern, for changes in singleton properties.  In addition, it fires the
74
 * Pipeline object that defines the processing to be performed for each request
75
 * following <code>ContainerEvent</code> events to listeners who register
75
 * received by the <code>invoke()</code> method of this class, utilizing the
76
 * themselves with <code>addContainerListener()</code>:
76
 * "Chain of Responsibility" design pattern.  A subclass should encapsulate its
77
 * <table border=1>
77
 * own processing functionality as a <code>Valve</code>, and configure this
78
 *   <tr>
78
 * Valve into the pipeline by calling <code>setBasic()</code>.
79
 *     <th>Type</th>
79
 * <p>
80
 *     <th>Data</th>
80
 * This implementation fires property change events, per the JavaBeans design
81
 *     <th>Description</th>
81
 * pattern, for changes in singleton properties.  In addition, it fires the
82
 *   </tr>
82
 * following <code>ContainerEvent</code> events to listeners who register
83
 *   <tr>
83
 * themselves with <code>addContainerListener()</code>:
84
 *     <td align=center><code>addChild</code></td>
84
 * <table border=1>
85
 *     <td align=center><code>Container</code></td>
85
 *   <tr>
86
 *     <td>Child container added to this Container.</td>
86
 *     <th>Type</th>
87
 *   </tr>
87
 *     <th>Data</th>
88
 *   <tr>
88
 *     <th>Description</th>
89
 *     <td align=center><code>addValve</code></td>
89
 *   </tr>
90
 *     <td align=center><code>Valve</code></td>
90
 *   <tr>
91
 *     <td>Valve added to this Container.</td>
91
 *     <td align=center><code>addChild</code></td>
92
 *   </tr>
92
 *     <td align=center><code>Container</code></td>
93
 *   <tr>
93
 *     <td>Child container added to this Container.</td>
94
 *     <td align=center><code>removeChild</code></td>
94
 *   </tr>
95
 *     <td align=center><code>Container</code></td>
95
 *   <tr>
96
 *     <td>Child container removed from this Container.</td>
96
 *     <td align=center><code>addValve</code></td>
97
 *   </tr>
97
 *     <td align=center><code>Valve</code></td>
98
 *   <tr>
98
 *     <td>Valve added to this Container.</td>
99
 *     <td align=center><code>removeValve</code></td>
99
 *   </tr>
100
 *     <td align=center><code>Valve</code></td>
100
 *   <tr>
101
 *     <td>Valve removed from this Container.</td>
101
 *     <td align=center><code>removeChild</code></td>
102
 *   </tr>
102
 *     <td align=center><code>Container</code></td>
103
 *   <tr>
103
 *     <td>Child container removed from this Container.</td>
104
 *     <td align=center><code>start</code></td>
104
 *   </tr>
105
 *     <td align=center><code>null</code></td>
105
 *   <tr>
106
 *     <td>Container was started.</td>
106
 *     <td align=center><code>removeValve</code></td>
107
 *   </tr>
107
 *     <td align=center><code>Valve</code></td>
108
 *   <tr>
108
 *     <td>Valve removed from this Container.</td>
109
 *     <td align=center><code>stop</code></td>
109
 *   </tr>
110
 *     <td align=center><code>null</code></td>
110
 *   <tr>
111
 *     <td>Container was stopped.</td>
111
 *     <td align=center><code>start</code></td>
112
 *   </tr>
112
 *     <td align=center><code>null</code></td>
113
 * </table>
113
 *     <td>Container was started.</td>
114
 * Subclasses that fire additional events should document them in the
114
 *   </tr>
115
 * class comments of the implementation class.
115
 *   <tr>
116
 * 
116
 *     <td align=center><code>stop</code></td>
117
 * TODO: Review synchronisation around background processing. See bug 47024. 
117
 *     <td align=center><code>null</code></td>
118
 * 
118
 *     <td>Container was stopped.</td>
119
 * @author Craig R. McClanahan
119
 *   </tr>
120
 */
120
 * </table>
121
public abstract class ContainerBase extends LifecycleMBeanBase
121
 * Subclasses that fire additional events should document them in the
122
        implements Container {
122
 * class comments of the implementation class.
123
123
 * 
124
    private static final org.apache.juli.logging.Log log=
124
 * TODO: Review synchronisation around background processing. See bug 47024. 
125
        org.apache.juli.logging.LogFactory.getLog( ContainerBase.class );
125
 * 
126
126
 * @author Craig R. McClanahan
127
    /**
127
 */
128
     * Perform addChild with the permissions of this class.
128
public abstract class ContainerBase extends LifecycleMBeanBase
129
     * addChild can be called with the XML parser on the stack,
129
        implements Container {
130
     * this allows the XML parser to have fewer privileges than
130
131
     * Tomcat.
131
    private static final org.apache.juli.logging.Log log=
132
     */
132
        org.apache.juli.logging.LogFactory.getLog( ContainerBase.class );
133
    protected class PrivilegedAddChild
133
134
        implements PrivilegedAction<Void> {
134
    /**
135
135
     * Perform addChild with the permissions of this class.
136
        private Container child;
136
     * addChild can be called with the XML parser on the stack,
137
137
     * this allows the XML parser to have fewer privileges than
138
        PrivilegedAddChild(Container child) {
138
     * Tomcat.
139
            this.child = child;
139
     */
140
        }
140
    protected class PrivilegedAddChild
141
141
        implements PrivilegedAction<Void> {
142
        @Override
142
143
        public Void run() {
143
        private Container child;
144
            addChildInternal(child);
144
145
            return null;
145
        PrivilegedAddChild(Container child) {
146
        }
146
            this.child = child;
147
147
        }
148
    }
148
149
149
        @Override
150
150
        public Void run() {
151
    // ----------------------------------------------------- Instance Variables
151
            addChildInternal(child);
152
152
            return null;
153
153
        }
154
    /**
154
155
     * The child Containers belonging to this Container, keyed by name.
155
    }
156
     */
156
157
    protected HashMap<String, Container> children =
157
158
        new HashMap<String, Container>();
158
    // ----------------------------------------------------- Instance Variables
159
159
160
160
161
    /**
161
    /**
162
     * The processor delay for this component.
162
     * The child Containers belonging to this Container, keyed by name.
163
     */
163
     */
164
    protected int backgroundProcessorDelay = -1;
164
    protected HashMap<String, Container> children =
165
165
        new HashMap<String, Container>();
166
166
167
    /**
167
168
     * The container event listeners for this Container.
168
    /**
169
     */
169
     * The processor delay for this component.
170
    protected ArrayList<ContainerListener> listeners = new ArrayList<ContainerListener>();
170
     */
171
171
    protected int backgroundProcessorDelay = -1;
172
172
173
    /**
173
174
     * The Loader implementation with which this Container is associated.
174
    /**
175
     */
175
     * The container event listeners for this Container.
176
    protected Loader loader = null;
176
     */
177
177
    protected ArrayList<ContainerListener> listeners = new ArrayList<ContainerListener>();
178
178
179
    /**
179
180
     * The Logger implementation with which this Container is associated.
180
    /**
181
     */
181
     * The Loader implementation with which this Container is associated.
182
    protected Log logger = null;
182
     */
183
183
    protected Loader loader = null;
184
184
185
    /**
185
186
     * Associated logger name.
186
    /**
187
     */
187
     * The Logger implementation with which this Container is associated.
188
    protected String logName = null;
188
     */
189
    
189
    protected Log logger = null;
190
190
191
    /**
191
192
     * The Manager implementation with which this Container is associated.
192
    /**
193
     */
193
     * Associated logger name.
194
    protected Manager manager = null;
194
     */
195
195
    protected String logName = null;
196
196
    
197
    /**
197
198
     * The cluster with which this Container is associated.
198
    /**
199
     */
199
     * The Manager implementation with which this Container is associated.
200
    protected Cluster cluster = null;
200
     */
201
201
    protected Manager manager = null;
202
    
202
203
    /**
203
204
     * The human-readable name of this Container.
204
    /**
205
     */
205
     * The cluster with which this Container is associated.
206
    protected String name = null;
206
     */
207
207
    protected Cluster cluster = null;
208
208
209
    /**
209
    
210
     * The parent Container to which this Container is a child.
210
    /**
211
     */
211
     * The human-readable name of this Container.
212
    protected Container parent = null;
212
     */
213
213
    protected String name = null;
214
214
215
    /**
215
216
     * The parent class loader to be configured when we install a Loader.
216
    /**
217
     */
217
     * The parent Container to which this Container is a child.
218
    protected ClassLoader parentClassLoader = null;
218
     */
219
219
    protected Container parent = null;
220
220
221
    /**
221
222
     * The Pipeline object with which this Container is associated.
222
    /**
223
     */
223
     * The parent class loader to be configured when we install a Loader.
224
    protected Pipeline pipeline =
224
     */
225
        CatalinaFactory.getFactory().createPipeline(this);
225
    protected ClassLoader parentClassLoader = null;
226
226
227
227
228
    /**
228
    /**
229
     * The Realm with which this Container is associated.
229
     * The Pipeline object with which this Container is associated.
230
     */
230
     */
231
    protected Realm realm = null;
231
    protected Pipeline pipeline =
232
232
        CatalinaFactory.getFactory().createPipeline(this);
233
233
234
    /**
234
235
     * The resources DirContext object with which this Container is associated.
235
    /**
236
     */
236
     * The Realm with which this Container is associated.
237
    protected DirContext resources = null;
237
     */
238
238
    protected Realm realm = null;
239
239
240
    /**
240
241
     * The string manager for this package.
241
    /**
242
     */
242
     * The resources DirContext object with which this Container is associated.
243
    protected static final StringManager sm =
243
     */
244
        StringManager.getManager(Constants.Package);
244
    protected DirContext resources = null;
245
245
246
246
247
    /**
247
    /**
248
     * Will children be started automatically when they are added.
248
     * The string manager for this package.
249
     */
249
     */
250
    protected boolean startChildren = true;
250
    protected static final StringManager sm =
251
251
        StringManager.getManager(Constants.Package);
252
    /**
252
253
     * The property change support for this component.
253
254
     */
254
    /**
255
    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
255
     * Will children be started automatically when they are added.
256
256
     */
257
257
    protected boolean startChildren = true;
258
    /**
258
259
     * The background thread.
259
    /**
260
     */
260
     * The property change support for this component.
261
    private Thread thread = null;
261
     */
262
262
    protected PropertyChangeSupport support = new PropertyChangeSupport(this);
263
263
264
    /**
264
265
     * The background thread completion semaphore.
265
    /**
266
     */
266
     * The background thread.
267
    private volatile boolean threadDone = false;
267
     */
268
268
    private Thread thread = null;
269
269
270
    /**
270
271
     * The access log to use for requests normally handled by this container
271
    /**
272
     * that have been handled earlier in the processing chain.
272
     * The background thread completion semaphore.
273
     */
273
     */
274
    protected volatile AccessLog accessLog = null;
274
    private volatile boolean threadDone = false;
275
    private volatile boolean accessLogScanComplete = false;
275
276
276
277
    // ------------------------------------------------------------- Properties
277
    /**
278
278
     * The access log to use for requests normally handled by this container
279
279
     * that have been handled earlier in the processing chain.
280
    /**
280
     */
281
     * Get the delay between the invocation of the backgroundProcess method on
281
    protected volatile AccessLog accessLog = null;
282
     * this container and its children. Child containers will not be invoked
282
    private volatile boolean accessLogScanComplete = false;
283
     * if their delay value is not negative (which would mean they are using 
283
284
     * their own thread). Setting this to a positive value will cause 
284
285
     * a thread to be spawn. After waiting the specified amount of time, 
285
    /**
286
     * the thread will invoke the executePeriodic method on this container 
286
     * The number of threads available to process start and stop events for any
287
     * and all its children.
287
     * children associated with this container.
288
     */
288
     */
289
    @Override
289
    private int startStopThreads = 1;
290
    public int getBackgroundProcessorDelay() {
290
    protected ThreadPoolExecutor startStopExecutor;
291
        return backgroundProcessorDelay;
291
    
292
    }
292
    // ------------------------------------------------------------- Properties
293
293
294
294
    @Override
295
    /**
295
    public int getStartStopThreads() {
296
     * Set the delay between the invocation of the execute method on this
296
        return startStopThreads;
297
     * container and its children.
297
    }
298
     * 
298
299
     * @param delay The delay in seconds between the invocation of 
299
    /**
300
     *              backgroundProcess methods
300
     * Handles the special values.
301
     */
301
     */
302
    @Override
302
    private int getStartStopThreadsInternal() {
303
    public void setBackgroundProcessorDelay(int delay) {
303
        int result = getStartStopThreads();
304
        backgroundProcessorDelay = delay;
304
        
305
    }
305
        // Positive values are unchanged
306
306
        if (result > 0) {
307
307
            return result;
308
    /**
308
        }
309
     * Return descriptive information about this Container implementation and
309
        
310
     * the corresponding version number, in the format
310
        // Zero == Runtime.getRuntime().availableProcessors()
311
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
311
        // -ve  == Runtime.getRuntime().availableProcessors() + value
312
     */
312
        // These two are the same
313
    @Override
313
        result = Runtime.getRuntime().availableProcessors() + result;
314
    public String getInfo() {
314
        if (result < 1) {
315
        return this.getClass().getName();
315
            result = 1;
316
    }
316
        }
317
317
        return result;
318
318
    }
319
    /**
319
320
     * Return the Loader with which this Container is associated.  If there is
320
    @Override
321
     * no associated Loader, return the Loader associated with our parent
321
    public void setStartStopThreads(int startStopThreads) {
322
     * Container (if any); otherwise, return <code>null</code>.
322
        this.startStopThreads = startStopThreads;
323
     */
323
        
324
    @Override
324
        // Use local copies to ensure thread safety
325
    public Loader getLoader() {
325
        ThreadPoolExecutor executor = startStopExecutor;
326
326
        if (executor != null) {
327
        if (loader != null)
327
            int newThreads = getStartStopThreadsInternal();
328
            return (loader);
328
            executor.setMaximumPoolSize(newThreads);
329
        if (parent != null)
329
            executor.setCorePoolSize(newThreads);
330
            return (parent.getLoader());
330
        }
331
        return (null);
331
    }
332
332
333
    }
333
334
334
    /**
335
335
     * Get the delay between the invocation of the backgroundProcess method on
336
    /**
336
     * this container and its children. Child containers will not be invoked
337
     * Set the Loader with which this Container is associated.
337
     * if their delay value is not negative (which would mean they are using 
338
     *
338
     * their own thread). Setting this to a positive value will cause 
339
     * @param loader The newly associated loader
339
     * a thread to be spawn. After waiting the specified amount of time, 
340
     */
340
     * the thread will invoke the executePeriodic method on this container 
341
    @Override
341
     * and all its children.
342
    public synchronized void setLoader(Loader loader) {
342
     */
343
343
    @Override
344
        // Change components if necessary
344
    public int getBackgroundProcessorDelay() {
345
        Loader oldLoader = this.loader;
345
        return backgroundProcessorDelay;
346
        if (oldLoader == loader)
346
    }
347
            return;
347
348
        this.loader = loader;
348
349
349
    /**
350
        // Stop the old component if necessary
350
     * Set the delay between the invocation of the execute method on this
351
        if (getState().isAvailable() && (oldLoader != null) &&
351
     * container and its children.
352
            (oldLoader instanceof Lifecycle)) {
352
     * 
353
            try {
353
     * @param delay The delay in seconds between the invocation of 
354
                ((Lifecycle) oldLoader).stop();
354
     *              backgroundProcess methods
355
            } catch (LifecycleException e) {
355
     */
356
                log.error("ContainerBase.setLoader: stop: ", e);
356
    @Override
357
            }
357
    public void setBackgroundProcessorDelay(int delay) {
358
        }
358
        backgroundProcessorDelay = delay;
359
359
    }
360
        // Start the new component if necessary
360
361
        if (loader != null)
361
362
            loader.setContainer(this);
362
    /**
363
        if (getState().isAvailable() && (loader != null) &&
363
     * Return descriptive information about this Container implementation and
364
            (loader instanceof Lifecycle)) {
364
     * the corresponding version number, in the format
365
            try {
365
     * <code>&lt;description&gt;/&lt;version&gt;</code>.
366
                ((Lifecycle) loader).start();
366
     */
367
            } catch (LifecycleException e) {
367
    @Override
368
                log.error("ContainerBase.setLoader: start: ", e);
368
    public String getInfo() {
369
            }
369
        return this.getClass().getName();
370
        }
370
    }
371
371
372
        // Report this property change to interested listeners
372
373
        support.firePropertyChange("loader", oldLoader, this.loader);
373
    /**
374
374
     * Return the Loader with which this Container is associated.  If there is
375
    }
375
     * no associated Loader, return the Loader associated with our parent
376
376
     * Container (if any); otherwise, return <code>null</code>.
377
377
     */
378
    /**
378
    @Override
379
     * Return the Logger for this Container.
379
    public Loader getLoader() {
380
     */
380
381
    @Override
381
        if (loader != null)
382
    public Log getLogger() {
382
            return (loader);
383
383
        if (parent != null)
384
        if (logger != null)
384
            return (parent.getLoader());
385
            return (logger);
385
        return (null);
386
        logger = LogFactory.getLog(logName());
386
387
        return (logger);
387
    }
388
388
389
    }
389
390
390
    /**
391
391
     * Set the Loader with which this Container is associated.
392
    /**
392
     *
393
     * Return the Manager with which this Container is associated.  If there is
393
     * @param loader The newly associated loader
394
     * no associated Manager, return the Manager associated with our parent
394
     */
395
     * Container (if any); otherwise return <code>null</code>.
395
    @Override
396
     */
396
    public synchronized void setLoader(Loader loader) {
397
    @Override
397
398
    public Manager getManager() {
398
        // Change components if necessary
399
399
        Loader oldLoader = this.loader;
400
        if (manager != null)
400
        if (oldLoader == loader)
401
            return (manager);
401
            return;
402
        if (parent != null)
402
        this.loader = loader;
403
            return (parent.getManager());
403
404
        return (null);
404
        // Stop the old component if necessary
405
405
        if (getState().isAvailable() && (oldLoader != null) &&
406
    }
406
            (oldLoader instanceof Lifecycle)) {
407
407
            try {
408
408
                ((Lifecycle) oldLoader).stop();
409
    /**
409
            } catch (LifecycleException e) {
410
     * Set the Manager with which this Container is associated.
410
                log.error("ContainerBase.setLoader: stop: ", e);
411
     *
411
            }
412
     * @param manager The newly associated Manager
412
        }
413
     */
413
414
    @Override
414
        // Start the new component if necessary
415
    public synchronized void setManager(Manager manager) {
415
        if (loader != null)
416
416
            loader.setContainer(this);
417
        // Change components if necessary
417
        if (getState().isAvailable() && (loader != null) &&
418
        Manager oldManager = this.manager;
418
            (loader instanceof Lifecycle)) {
419
        if (oldManager == manager)
419
            try {
420
            return;
420
                ((Lifecycle) loader).start();
421
        this.manager = manager;
421
            } catch (LifecycleException e) {
422
422
                log.error("ContainerBase.setLoader: start: ", e);
423
        // Stop the old component if necessary
423
            }
424
        if (getState().isAvailable() && (oldManager != null) &&
424
        }
425
            (oldManager instanceof Lifecycle)) {
425
426
            try {
426
        // Report this property change to interested listeners
427
                ((Lifecycle) oldManager).stop();
427
        support.firePropertyChange("loader", oldLoader, this.loader);
428
            } catch (LifecycleException e) {
428
429
                log.error("ContainerBase.setManager: stop: ", e);
429
    }
430
            }
430
431
        }
431
432
432
    /**
433
        // Start the new component if necessary
433
     * Return the Logger for this Container.
434
        if (manager != null)
434
     */
435
            manager.setContainer(this);
435
    @Override
436
        if (getState().isAvailable() && (manager != null) &&
436
    public Log getLogger() {
437
            (manager instanceof Lifecycle)) {
437
438
            try {
438
        if (logger != null)
439
                ((Lifecycle) manager).start();
439
            return (logger);
440
            } catch (LifecycleException e) {
440
        logger = LogFactory.getLog(logName());
441
                log.error("ContainerBase.setManager: start: ", e);
441
        return (logger);
442
            }
442
443
        }
443
    }
444
444
445
        // Report this property change to interested listeners
445
446
        support.firePropertyChange("manager", oldManager, this.manager);
446
    /**
447
447
     * Return the Manager with which this Container is associated.  If there is
448
    }
448
     * no associated Manager, return the Manager associated with our parent
449
449
     * Container (if any); otherwise return <code>null</code>.
450
450
     */
451
    /**
451
    @Override
452
     * Return an object which may be utilized for mapping to this component.
452
    public Manager getManager() {
453
     */
453
454
    @Override
454
        if (manager != null)
455
    public Object getMappingObject() {
455
            return (manager);
456
        return this;
456
        if (parent != null)
457
    }
457
            return (parent.getManager());
458
458
        return (null);
459
459
460
    /**
460
    }
461
     * Return the Cluster with which this Container is associated.  If there is
461
462
     * no associated Cluster, return the Cluster associated with our parent
462
463
     * Container (if any); otherwise return <code>null</code>.
463
    /**
464
     */
464
     * Set the Manager with which this Container is associated.
465
    @Override
465
     *
466
    public Cluster getCluster() {
466
     * @param manager The newly associated Manager
467
        if (cluster != null)
467
     */
468
            return (cluster);
468
    @Override
469
469
    public synchronized void setManager(Manager manager) {
470
        if (parent != null)
470
471
            return (parent.getCluster());
471
        // Change components if necessary
472
472
        Manager oldManager = this.manager;
473
        return (null);
473
        if (oldManager == manager)
474
    }
474
            return;
475
475
        this.manager = manager;
476
476
477
    /**
477
        // Stop the old component if necessary
478
     * Set the Cluster with which this Container is associated.
478
        if (getState().isAvailable() && (oldManager != null) &&
479
     *
479
            (oldManager instanceof Lifecycle)) {
480
     * @param cluster The newly associated Cluster
480
            try {
481
     */
481
                ((Lifecycle) oldManager).stop();
482
    @Override
482
            } catch (LifecycleException e) {
483
    public synchronized void setCluster(Cluster cluster) {
483
                log.error("ContainerBase.setManager: stop: ", e);
484
        // Change components if necessary
484
            }
485
        Cluster oldCluster = this.cluster;
485
        }
486
        if (oldCluster == cluster)
486
487
            return;
487
        // Start the new component if necessary
488
        this.cluster = cluster;
488
        if (manager != null)
489
489
            manager.setContainer(this);
490
        // Stop the old component if necessary
490
        if (getState().isAvailable() && (manager != null) &&
491
        if (getState().isAvailable() && (oldCluster != null) &&
491
            (manager instanceof Lifecycle)) {
492
            (oldCluster instanceof Lifecycle)) {
492
            try {
493
            try {
493
                ((Lifecycle) manager).start();
494
                ((Lifecycle) oldCluster).stop();
494
            } catch (LifecycleException e) {
495
            } catch (LifecycleException e) {
495
                log.error("ContainerBase.setManager: start: ", e);
496
                log.error("ContainerBase.setCluster: stop: ", e);
496
            }
497
            }
497
        }
498
        }
498
499
499
        // Report this property change to interested listeners
500
        // Start the new component if necessary
500
        support.firePropertyChange("manager", oldManager, this.manager);
501
        if (cluster != null)
501
502
            cluster.setContainer(this);
502
    }
503
503
504
        if (getState().isAvailable() && (cluster != null) &&
504
505
            (cluster instanceof Lifecycle)) {
505
    /**
506
            try {
506
     * Return an object which may be utilized for mapping to this component.
507
                ((Lifecycle) cluster).start();
507
     */
508
            } catch (LifecycleException e) {
508
    @Override
509
                log.error("ContainerBase.setCluster: start: ", e);
509
    public Object getMappingObject() {
510
            }
510
        return this;
511
        }
511
    }
512
512
513
        // Report this property change to interested listeners
513
514
        support.firePropertyChange("cluster", oldCluster, this.cluster);
514
    /**
515
    }
515
     * Return the Cluster with which this Container is associated.  If there is
516
516
     * no associated Cluster, return the Cluster associated with our parent
517
517
     * Container (if any); otherwise return <code>null</code>.
518
    /**
518
     */
519
     * Return a name string (suitable for use by humans) that describes this
519
    @Override
520
     * Container.  Within the set of child containers belonging to a particular
520
    public Cluster getCluster() {
521
     * parent, Container names must be unique.
521
        if (cluster != null)
522
     */
522
            return (cluster);
523
    @Override
523
524
    public String getName() {
524
        if (parent != null)
525
525
            return (parent.getCluster());
526
        return (name);
526
527
527
        return (null);
528
    }
528
    }
529
529
530
530
531
    /**
531
    /**
532
     * Set a name string (suitable for use by humans) that describes this
532
     * Set the Cluster with which this Container is associated.
533
     * Container.  Within the set of child containers belonging to a particular
533
     *
534
     * parent, Container names must be unique.
534
     * @param cluster The newly associated Cluster
535
     *
535
     */
536
     * @param name New name of this container
536
    @Override
537
     *
537
    public synchronized void setCluster(Cluster cluster) {
538
     * @exception IllegalStateException if this Container has already been
538
        // Change components if necessary
539
     *  added to the children of a parent Container (after which the name
539
        Cluster oldCluster = this.cluster;
540
     *  may not be changed)
540
        if (oldCluster == cluster)
541
     */
541
            return;
542
    @Override
542
        this.cluster = cluster;
543
    public void setName(String name) {
543
544
544
        // Stop the old component if necessary
545
        String oldName = this.name;
545
        if (getState().isAvailable() && (oldCluster != null) &&
546
        this.name = name;
546
            (oldCluster instanceof Lifecycle)) {
547
        support.firePropertyChange("name", oldName, this.name);
547
            try {
548
    }
548
                ((Lifecycle) oldCluster).stop();
549
549
            } catch (LifecycleException e) {
550
550
                log.error("ContainerBase.setCluster: stop: ", e);
551
    /**
551
            }
552
     * Return if children of this container will be started automatically when
552
        }
553
     * they are added to this container.
553
554
     */
554
        // Start the new component if necessary
555
    public boolean getStartChildren() {
555
        if (cluster != null)
556
556
            cluster.setContainer(this);
557
        return (startChildren);
557
558
558
        if (getState().isAvailable() && (cluster != null) &&
559
    }
559
            (cluster instanceof Lifecycle)) {
560
560
            try {
561
561
                ((Lifecycle) cluster).start();
562
    /**
562
            } catch (LifecycleException e) {
563
     * Set if children of this container will be started automatically when
563
                log.error("ContainerBase.setCluster: start: ", e);
564
     * they are added to this container.
564
            }
565
     *
565
        }
566
     * @param startChildren New value of the startChildren flag
566
567
     */
567
        // Report this property change to interested listeners
568
    public void setStartChildren(boolean startChildren) {
568
        support.firePropertyChange("cluster", oldCluster, this.cluster);
569
569
    }
570
        boolean oldStartChildren = this.startChildren;
570
571
        this.startChildren = startChildren;
571
572
        support.firePropertyChange("startChildren", oldStartChildren, this.startChildren);
572
    /**
573
    }
573
     * Return a name string (suitable for use by humans) that describes this
574
574
     * Container.  Within the set of child containers belonging to a particular
575
575
     * parent, Container names must be unique.
576
    /**
576
     */
577
     * Return the Container for which this Container is a child, if there is
577
    @Override
578
     * one.  If there is no defined parent, return <code>null</code>.
578
    public String getName() {
579
     */
579
580
    @Override
580
        return (name);
581
    public Container getParent() {
581
582
582
    }
583
        return (parent);
583
584
584
585
    }
585
    /**
586
586
     * Set a name string (suitable for use by humans) that describes this
587
587
     * Container.  Within the set of child containers belonging to a particular
588
    /**
588
     * parent, Container names must be unique.
589
     * Set the parent Container to which this Container is being added as a
589
     *
590
     * child.  This Container may refuse to become attached to the specified
590
     * @param name New name of this container
591
     * Container by throwing an exception.
591
     *
592
     *
592
     * @exception IllegalStateException if this Container has already been
593
     * @param container Container to which this Container is being added
593
     *  added to the children of a parent Container (after which the name
594
     *  as a child
594
     *  may not be changed)
595
     *
595
     */
596
     * @exception IllegalArgumentException if this Container refuses to become
596
    @Override
597
     *  attached to the specified Container
597
    public void setName(String name) {
598
     */
598
599
    @Override
599
        String oldName = this.name;
600
    public void setParent(Container container) {
600
        this.name = name;
601
601
        support.firePropertyChange("name", oldName, this.name);
602
        Container oldParent = this.parent;
602
    }
603
        this.parent = container;
603
604
        support.firePropertyChange("parent", oldParent, this.parent);
604
605
605
    /**
606
    }
606
     * Return if children of this container will be started automatically when
607
607
     * they are added to this container.
608
608
     */
609
    /**
609
    public boolean getStartChildren() {
610
     * Return the parent class loader (if any) for this web application.
610
611
     * This call is meaningful only <strong>after</strong> a Loader has
611
        return (startChildren);
612
     * been configured.
612
613
     */
613
    }
614
    @Override
614
615
    public ClassLoader getParentClassLoader() {
615
616
        if (parentClassLoader != null)
616
    /**
617
            return (parentClassLoader);
617
     * Set if children of this container will be started automatically when
618
        if (parent != null) {
618
     * they are added to this container.
619
            return (parent.getParentClassLoader());
619
     *
620
        }
620
     * @param startChildren New value of the startChildren flag
621
        return (ClassLoader.getSystemClassLoader());
621
     */
622
622
    public void setStartChildren(boolean startChildren) {
623
    }
623
624
624
        boolean oldStartChildren = this.startChildren;
625
625
        this.startChildren = startChildren;
626
    /**
626
        support.firePropertyChange("startChildren", oldStartChildren, this.startChildren);
627
     * Set the parent class loader (if any) for this web application.
627
    }
628
     * This call is meaningful only <strong>before</strong> a Loader has
628
629
     * been configured, and the specified value (if non-null) should be
629
630
     * passed as an argument to the class loader constructor.
630
    /**
631
     *
631
     * Return the Container for which this Container is a child, if there is
632
     *
632
     * one.  If there is no defined parent, return <code>null</code>.
633
     * @param parent The new parent class loader
633
     */
634
     */
634
    @Override
635
    @Override
635
    public Container getParent() {
636
    public void setParentClassLoader(ClassLoader parent) {
636
637
        ClassLoader oldParentClassLoader = this.parentClassLoader;
637
        return (parent);
638
        this.parentClassLoader = parent;
638
639
        support.firePropertyChange("parentClassLoader", oldParentClassLoader,
639
    }
640
                                   this.parentClassLoader);
640
641
641
642
    }
642
    /**
643
643
     * Set the parent Container to which this Container is being added as a
644
644
     * child.  This Container may refuse to become attached to the specified
645
    /**
645
     * Container by throwing an exception.
646
     * Return the Pipeline object that manages the Valves associated with
646
     *
647
     * this Container.
647
     * @param container Container to which this Container is being added
648
     */
648
     *  as a child
649
    @Override
649
     *
650
    public Pipeline getPipeline() {
650
     * @exception IllegalArgumentException if this Container refuses to become
651
651
     *  attached to the specified Container
652
        return (this.pipeline);
652
     */
653
653
    @Override
654
    }
654
    public void setParent(Container container) {
655
655
656
656
        Container oldParent = this.parent;
657
    /**
657
        this.parent = container;
658
     * Return the Realm with which this Container is associated.  If there is
658
        support.firePropertyChange("parent", oldParent, this.parent);
659
     * no associated Realm, return the Realm associated with our parent
659
660
     * Container (if any); otherwise return <code>null</code>.
660
    }
661
     */
661
662
    @Override
662
663
    public Realm getRealm() {
663
    /**
664
664
     * Return the parent class loader (if any) for this web application.
665
        if (realm != null)
665
     * This call is meaningful only <strong>after</strong> a Loader has
666
            return (realm);
666
     * been configured.
667
        if (parent != null)
667
     */
668
            return (parent.getRealm());
668
    @Override
669
        return (null);
669
    public ClassLoader getParentClassLoader() {
670
670
        if (parentClassLoader != null)
671
    }
671
            return (parentClassLoader);
672
672
        if (parent != null) {
673
673
            return (parent.getParentClassLoader());
674
    /**
674
        }
675
     * Set the Realm with which this Container is associated.
675
        return (ClassLoader.getSystemClassLoader());
676
     *
676
677
     * @param realm The newly associated Realm
677
    }
678
     */
678
679
    @Override
679
680
    public synchronized void setRealm(Realm realm) {
680
    /**
681
681
     * Set the parent class loader (if any) for this web application.
682
        // Change components if necessary
682
     * This call is meaningful only <strong>before</strong> a Loader has
683
        Realm oldRealm = this.realm;
683
     * been configured, and the specified value (if non-null) should be
684
        if (oldRealm == realm)
684
     * passed as an argument to the class loader constructor.
685
            return;
685
     *
686
        this.realm = realm;
686
     *
687
687
     * @param parent The new parent class loader
688
        // Stop the old component if necessary
688
     */
689
        if (getState().isAvailable() && (oldRealm != null) &&
689
    @Override
690
            (oldRealm instanceof Lifecycle)) {
690
    public void setParentClassLoader(ClassLoader parent) {
691
            try {
691
        ClassLoader oldParentClassLoader = this.parentClassLoader;
692
                ((Lifecycle) oldRealm).stop();
692
        this.parentClassLoader = parent;
693
            } catch (LifecycleException e) {
693
        support.firePropertyChange("parentClassLoader", oldParentClassLoader,
694
                log.error("ContainerBase.setRealm: stop: ", e);
694
                                   this.parentClassLoader);
695
            }
695
696
        }
696
    }
697
697
698
        // Start the new component if necessary
698
699
        if (realm != null)
699
    /**
700
            realm.setContainer(this);
700
     * Return the Pipeline object that manages the Valves associated with
701
        if (getState().isAvailable() && (realm != null) &&
701
     * this Container.
702
            (realm instanceof Lifecycle)) {
702
     */
703
            try {
703
    @Override
704
                ((Lifecycle) realm).start();
704
    public Pipeline getPipeline() {
705
            } catch (LifecycleException e) {
705
706
                log.error("ContainerBase.setRealm: start: ", e);
706
        return (this.pipeline);
707
            }
707
708
        }
708
    }
709
709
710
        // Report this property change to interested listeners
710
711
        support.firePropertyChange("realm", oldRealm, this.realm);
711
    /**
712
712
     * Return the Realm with which this Container is associated.  If there is
713
    }
713
     * no associated Realm, return the Realm associated with our parent
714
714
     * Container (if any); otherwise return <code>null</code>.
715
715
     */
716
    /**
716
    @Override
717
      * Return the resources DirContext object with which this Container is
717
    public Realm getRealm() {
718
      * associated.  If there is no associated resources object, return the
718
719
      * resources associated with our parent Container (if any); otherwise
719
        if (realm != null)
720
      * return <code>null</code>.
720
            return (realm);
721
     */
721
        if (parent != null)
722
    @Override
722
            return (parent.getRealm());
723
    public DirContext getResources() {
723
        return (null);
724
        if (resources != null)
724
725
            return (resources);
725
    }
726
        if (parent != null)
726
727
            return (parent.getResources());
727
728
        return (null);
728
    /**
729
729
     * Set the Realm with which this Container is associated.
730
    }
730
     *
731
731
     * @param realm The newly associated Realm
732
732
     */
733
    /**
733
    @Override
734
     * Set the resources DirContext object with which this Container is
734
    public synchronized void setRealm(Realm realm) {
735
     * associated.
735
736
     *
736
        // Change components if necessary
737
     * @param resources The newly associated DirContext
737
        Realm oldRealm = this.realm;
738
     */
738
        if (oldRealm == realm)
739
    @Override
739
            return;
740
    public synchronized void setResources(DirContext resources) {
740
        this.realm = realm;
741
        // Called from StandardContext.setResources()
741
742
        //              <- StandardContext.start() 
742
        // Stop the old component if necessary
743
        //              <- ContainerBase.addChildInternal() 
743
        if (getState().isAvailable() && (oldRealm != null) &&
744
744
            (oldRealm instanceof Lifecycle)) {
745
        // Change components if necessary
745
            try {
746
        DirContext oldResources = this.resources;
746
                ((Lifecycle) oldRealm).stop();
747
        if (oldResources == resources)
747
            } catch (LifecycleException e) {
748
            return;
748
                log.error("ContainerBase.setRealm: stop: ", e);
749
        Hashtable<String, String> env = new Hashtable<String, String>();
749
            }
750
        if (getParent() != null)
750
        }
751
            env.put(ProxyDirContext.HOST, getParent().getName());
751
752
        env.put(ProxyDirContext.CONTEXT, getName());
752
        // Start the new component if necessary
753
        this.resources = new ProxyDirContext(env, resources);
753
        if (realm != null)
754
        // Report this property change to interested listeners
754
            realm.setContainer(this);
755
        support.firePropertyChange("resources", oldResources, this.resources);
755
        if (getState().isAvailable() && (realm != null) &&
756
756
            (realm instanceof Lifecycle)) {
757
    }
757
            try {
758
758
                ((Lifecycle) realm).start();
759
759
            } catch (LifecycleException e) {
760
    // ------------------------------------------------------ Container Methods
760
                log.error("ContainerBase.setRealm: start: ", e);
761
761
            }
762
762
        }
763
    /**
763
764
     * Add a new child Container to those associated with this Container,
764
        // Report this property change to interested listeners
765
     * if supported.  Prior to adding this Container to the set of children,
765
        support.firePropertyChange("realm", oldRealm, this.realm);
766
     * the child's <code>setParent()</code> method must be called, with this
766
767
     * Container as an argument.  This method may thrown an
767
    }
768
     * <code>IllegalArgumentException</code> if this Container chooses not
768
769
     * to be attached to the specified Container, in which case it is not added
769
770
     *
770
    /**
771
     * @param child New child Container to be added
771
      * Return the resources DirContext object with which this Container is
772
     *
772
      * associated.  If there is no associated resources object, return the
773
     * @exception IllegalArgumentException if this exception is thrown by
773
      * resources associated with our parent Container (if any); otherwise
774
     *  the <code>setParent()</code> method of the child Container
774
      * return <code>null</code>.
775
     * @exception IllegalArgumentException if the new child does not have
775
     */
776
     *  a name unique from that of existing children of this Container
776
    @Override
777
     * @exception IllegalStateException if this Container does not support
777
    public DirContext getResources() {
778
     *  child Containers
778
        if (resources != null)
779
     */
779
            return (resources);
780
    @Override
780
        if (parent != null)
781
    public void addChild(Container child) {
781
            return (parent.getResources());
782
        if (Globals.IS_SECURITY_ENABLED) {
782
        return (null);
783
            PrivilegedAction<Void> dp =
783
784
                new PrivilegedAddChild(child);
784
    }
785
            AccessController.doPrivileged(dp);
785
786
        } else {
786
787
            addChildInternal(child);
787
    /**
788
        }
788
     * Set the resources DirContext object with which this Container is
789
    }
789
     * associated.
790
790
     *
791
    private void addChildInternal(Container child) {
791
     * @param resources The newly associated DirContext
792
792
     */
793
        if( log.isDebugEnabled() )
793
    @Override
794
            log.debug("Add child " + child + " " + this);
794
    public synchronized void setResources(DirContext resources) {
795
        synchronized(children) {
795
        // Called from StandardContext.setResources()
796
            if (children.get(child.getName()) != null)
796
        //              <- StandardContext.start() 
797
                throw new IllegalArgumentException("addChild:  Child name '" +
797
        //              <- ContainerBase.addChildInternal() 
798
                                                   child.getName() +
798
799
                                                   "' is not unique");
799
        // Change components if necessary
800
            child.setParent(this);  // May throw IAE
800
        DirContext oldResources = this.resources;
801
            children.put(child.getName(), child);
801
        if (oldResources == resources)
802
        }
802
            return;
803
803
        Hashtable<String, String> env = new Hashtable<String, String>();
804
        // Start child
804
        if (getParent() != null)
805
        // Don't do this inside sync block - start can be a slow process and
805
            env.put(ProxyDirContext.HOST, getParent().getName());
806
        // locking the children object can cause problems elsewhere
806
        env.put(ProxyDirContext.CONTEXT, getName());
807
        if ((getState().isAvailable() ||
807
        this.resources = new ProxyDirContext(env, resources);
808
                LifecycleState.STARTING_PREP.equals(getState())) &&
808
        // Report this property change to interested listeners
809
                startChildren) {
809
        support.firePropertyChange("resources", oldResources, this.resources);
810
            boolean success = false;
810
811
            try {
811
    }
812
                child.start();
812
813
                success = true;
813
814
            } catch (LifecycleException e) {
814
    // ------------------------------------------------------ Container Methods
815
                log.error("ContainerBase.addChild: start: ", e);
815
816
                throw new IllegalStateException
816
817
                    ("ContainerBase.addChild: start: " + e);
817
    /**
818
            } finally {
818
     * Add a new child Container to those associated with this Container,
819
                if (!success) {
819
     * if supported.  Prior to adding this Container to the set of children,
820
                    synchronized (children) {
820
     * the child's <code>setParent()</code> method must be called, with this
821
                        children.remove(child.getName());
821
     * Container as an argument.  This method may thrown an
822
                    }
822
     * <code>IllegalArgumentException</code> if this Container chooses not
823
                }
823
     * to be attached to the specified Container, in which case it is not added
824
            }
824
     *
825
        }
825
     * @param child New child Container to be added
826
826
     *
827
        fireContainerEvent(ADD_CHILD_EVENT, child);
827
     * @exception IllegalArgumentException if this exception is thrown by
828
    }
828
     *  the <code>setParent()</code> method of the child Container
829
829
     * @exception IllegalArgumentException if the new child does not have
830
830
     *  a name unique from that of existing children of this Container
831
    /**
831
     * @exception IllegalStateException if this Container does not support
832
     * Add a container event listener to this component.
832
     *  child Containers
833
     *
833
     */
834
     * @param listener The listener to add
834
    @Override
835
     */
835
    public void addChild(Container child) {
836
    @Override
836
        if (Globals.IS_SECURITY_ENABLED) {
837
    public void addContainerListener(ContainerListener listener) {
837
            PrivilegedAction<Void> dp =
838
838
                new PrivilegedAddChild(child);
839
        synchronized (listeners) {
839
            AccessController.doPrivileged(dp);
840
            listeners.add(listener);
840
        } else {
841
        }
841
            addChildInternal(child);
842
842
        }
843
    }
843
    }
844
844
845
845
    private void addChildInternal(Container child) {
846
    /**
846
847
     * Add a property change listener to this component.
847
        if( log.isDebugEnabled() )
848
     *
848
            log.debug("Add child " + child + " " + this);
849
     * @param listener The listener to add
849
        synchronized(children) {
850
     */
850
            if (children.get(child.getName()) != null)
851
    @Override
851
                throw new IllegalArgumentException("addChild:  Child name '" +
852
    public void addPropertyChangeListener(PropertyChangeListener listener) {
852
                                                   child.getName() +
853
853
                                                   "' is not unique");
854
        support.addPropertyChangeListener(listener);
854
            child.setParent(this);  // May throw IAE
855
855
            children.put(child.getName(), child);
856
    }
856
        }
857
857
858
858
        // Start child
859
    /**
859
        // Don't do this inside sync block - start can be a slow process and
860
     * Return the child Container, associated with this Container, with
860
        // locking the children object can cause problems elsewhere
861
     * the specified name (if any); otherwise, return <code>null</code>
861
        if ((getState().isAvailable() ||
862
     *
862
                LifecycleState.STARTING_PREP.equals(getState())) &&
863
     * @param name Name of the child Container to be retrieved
863
                startChildren) {
864
     */
864
            boolean success = false;
865
    @Override
865
            try {
866
    public Container findChild(String name) {
866
                child.start();
867
867
                success = true;
868
        if (name == null)
868
            } catch (LifecycleException e) {
869
            return (null);
869
                log.error("ContainerBase.addChild: start: ", e);
870
        synchronized (children) {
870
                throw new IllegalStateException
871
            return children.get(name);
871
                    ("ContainerBase.addChild: start: " + e);
872
        }
872
            } finally {
873
873
                if (!success) {
874
    }
874
                    synchronized (children) {
875
875
                        children.remove(child.getName());
876
876
                    }
877
    /**
877
                }
878
     * Return the set of children Containers associated with this Container.
878
            }
879
     * If this Container has no children, a zero-length array is returned.
879
        }
880
     */
880
881
    @Override
881
        fireContainerEvent(ADD_CHILD_EVENT, child);
882
    public Container[] findChildren() {
882
    }
883
883
884
        synchronized (children) {
884
885
            Container results[] = new Container[children.size()];
885
    /**
886
            return children.values().toArray(results);
886
     * Add a container event listener to this component.
887
        }
887
     *
888
888
     * @param listener The listener to add
889
    }
889
     */
890
890
    @Override
891
891
    public void addContainerListener(ContainerListener listener) {
892
    /**
892
893
     * Return the set of container listeners associated with this Container.
893
        synchronized (listeners) {
894
     * If this Container has no registered container listeners, a zero-length
894
            listeners.add(listener);
895
     * array is returned.
895
        }
896
     */
896
897
    @Override
897
    }
898
    public ContainerListener[] findContainerListeners() {
898
899
899
900
        synchronized (listeners) {
900
    /**
901
            ContainerListener[] results = 
901
     * Add a property change listener to this component.
902
                new ContainerListener[listeners.size()];
902
     *
903
            return listeners.toArray(results);
903
     * @param listener The listener to add
904
        }
904
     */
905
905
    @Override
906
    }
906
    public void addPropertyChangeListener(PropertyChangeListener listener) {
907
907
908
908
        support.addPropertyChangeListener(listener);
909
    /**
909
910
     * Process the specified Request, to produce the corresponding Response,
910
    }
911
     * by invoking the first Valve in our pipeline (if any), or the basic
911
912
     * Valve otherwise.
912
913
     *
913
    /**
914
     * @param request Request to be processed
914
     * Return the child Container, associated with this Container, with
915
     * @param response Response to be produced
915
     * the specified name (if any); otherwise, return <code>null</code>
916
     *
916
     *
917
     * @exception IllegalStateException if neither a pipeline or a basic
917
     * @param name Name of the child Container to be retrieved
918
     *  Valve have been configured for this Container
918
     */
919
     * @exception IOException if an input/output error occurred while
919
    @Override
920
     *  processing
920
    public Container findChild(String name) {
921
     * @exception ServletException if a ServletException was thrown
921
922
     *  while processing this request
922
        if (name == null)
923
     */
923
            return (null);
924
    @Override
924
        synchronized (children) {
925
    public void invoke(Request request, Response response)
925
            return children.get(name);
926
        throws IOException, ServletException {
926
        }
927
927
928
        pipeline.getFirst().invoke(request, response);
928
    }
929
929
930
    }
930
931
931
    /**
932
932
     * Return the set of children Containers associated with this Container.
933
    /**
933
     * If this Container has no children, a zero-length array is returned.
934
     * Remove an existing child Container from association with this parent
934
     */
935
     * Container.
935
    @Override
936
     *
936
    public Container[] findChildren() {
937
     * @param child Existing child Container to be removed
937
938
     */
938
        synchronized (children) {
939
    @Override
939
            Container results[] = new Container[children.size()];
940
    public void removeChild(Container child) {
940
            return children.values().toArray(results);
941
941
        }
942
        if (child == null) {
942
943
            return;
943
    }
944
        }
944
945
        
945
946
        synchronized(children) {
946
    /**
947
            if (children.get(child.getName()) == null)
947
     * Return the set of container listeners associated with this Container.
948
                return;
948
     * If this Container has no registered container listeners, a zero-length
949
            children.remove(child.getName());
949
     * array is returned.
950
        }
950
     */
951
        
951
    @Override
952
        try {
952
    public ContainerListener[] findContainerListeners() {
953
            if (child.getState().isAvailable()) {
953
954
                child.stop();
954
        synchronized (listeners) {
955
            }
955
            ContainerListener[] results = 
956
        } catch (LifecycleException e) {
956
                new ContainerListener[listeners.size()];
957
            log.error("ContainerBase.removeChild: stop: ", e);
957
            return listeners.toArray(results);
958
        }
958
        }
959
        
959
960
        fireContainerEvent(REMOVE_CHILD_EVENT, child);
960
    }
961
        
961
962
        try {
962
963
            // child.destroy() may have already been called which would have
963
    /**
964
            // triggered this call. If that is the case, no need to destroy the
964
     * Process the specified Request, to produce the corresponding Response,
965
            // child again.
965
     * by invoking the first Valve in our pipeline (if any), or the basic
966
            if (!LifecycleState.DESTROYING.equals(child.getState())) {
966
     * Valve otherwise.
967
                child.destroy();
967
     *
968
            }
968
     * @param request Request to be processed
969
        } catch (LifecycleException e) {
969
     * @param response Response to be produced
970
            log.error("ContainerBase.removeChild: destroy: ", e);
970
     *
971
        }
971
     * @exception IllegalStateException if neither a pipeline or a basic
972
972
     *  Valve have been configured for this Container
973
    }
973
     * @exception IOException if an input/output error occurred while
974
974
     *  processing
975
975
     * @exception ServletException if a ServletException was thrown
976
    /**
976
     *  while processing this request
977
     * Remove a container event listener from this component.
977
     */
978
     *
978
    @Override
979
     * @param listener The listener to remove
979
    public void invoke(Request request, Response response)
980
     */
980
        throws IOException, ServletException {
981
    @Override
981
982
    public void removeContainerListener(ContainerListener listener) {
982
        pipeline.getFirst().invoke(request, response);
983
983
984
        synchronized (listeners) {
984
    }
985
            listeners.remove(listener);
985
986
        }
986
987
987
    /**
988
    }
988
     * Remove an existing child Container from association with this parent
989
989
     * Container.
990
990
     *
991
    /**
991
     * @param child Existing child Container to be removed
992
     * Remove a property change listener from this component.
992
     */
993
     *
993
    @Override
994
     * @param listener The listener to remove
994
    public void removeChild(Container child) {
995
     */
995
996
    @Override
996
        if (child == null) {
997
    public void removePropertyChangeListener(PropertyChangeListener listener) {
997
            return;
998
998
        }
999
        support.removePropertyChangeListener(listener);
999
        
1000
1000
        synchronized(children) {
1001
    }
1001
            if (children.get(child.getName()) == null)
1002
1002
                return;
1003
1003
            children.remove(child.getName());
1004
    /**
1004
        }
1005
     * Start this component and implement the requirements
1005
        
1006
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
1006
        try {
1007
     *
1007
            if (child.getState().isAvailable()) {
1008
     * @exception LifecycleException if this component detects a fatal error
1008
                child.stop();
1009
     *  that prevents this component from being used
1009
            }
1010
     */
1010
        } catch (LifecycleException e) {
1011
    @Override
1011
            log.error("ContainerBase.removeChild: stop: ", e);
1012
    protected synchronized void startInternal() throws LifecycleException {
1012
        }
1013
1013
        
1014
        // Start our subordinate components, if any
1014
        fireContainerEvent(REMOVE_CHILD_EVENT, child);
1015
        if ((loader != null) && (loader instanceof Lifecycle))
1015
        
1016
            ((Lifecycle) loader).start();
1016
        try {
1017
        logger = null;
1017
            // child.destroy() may have already been called which would have
1018
        getLogger();
1018
            // triggered this call. If that is the case, no need to destroy the
1019
        if ((logger != null) && (logger instanceof Lifecycle))
1019
            // child again.
1020
            ((Lifecycle) logger).start();
1020
            if (!LifecycleState.DESTROYING.equals(child.getState())) {
1021
        if ((manager != null) && (manager instanceof Lifecycle))
1021
                child.destroy();
1022
            ((Lifecycle) manager).start();
1022
            }
1023
        if ((cluster != null) && (cluster instanceof Lifecycle))
1023
        } catch (LifecycleException e) {
1024
            ((Lifecycle) cluster).start();
1024
            log.error("ContainerBase.removeChild: destroy: ", e);
1025
        if ((realm != null) && (realm instanceof Lifecycle))
1025
        }
1026
            ((Lifecycle) realm).start();
1026
1027
        if ((resources != null) && (resources instanceof Lifecycle))
1027
    }
1028
            ((Lifecycle) resources).start();
1028
1029
1029
1030
        // Start our child containers, if any
1030
    /**
1031
        Container children[] = findChildren();
1031
     * Remove a container event listener from this component.
1032
        for (int i = 0; i < children.length; i++) {
1032
     *
1033
            children[i].start();
1033
     * @param listener The listener to remove
1034
        }
1034
     */
1035
1035
    @Override
1036
        // Start the Valves in our pipeline (including the basic), if any
1036
    public void removeContainerListener(ContainerListener listener) {
1037
        if (pipeline instanceof Lifecycle)
1037
1038
            ((Lifecycle) pipeline).start();
1038
        synchronized (listeners) {
1039
1039
            listeners.remove(listener);
1040
1040
        }
1041
        setState(LifecycleState.STARTING);
1041
1042
1042
    }
1043
        // Start our thread
1043
1044
        threadStart();
1044
1045
1045
    /**
1046
    }
1046
     * Remove a property change listener from this component.
1047
1047
     *
1048
1048
     * @param listener The listener to remove
1049
    /**
1049
     */
1050
     * Stop this component and implement the requirements
1050
    @Override
1051
     * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
1051
    public void removePropertyChangeListener(PropertyChangeListener listener) {
1052
     *
1052
1053
     * @exception LifecycleException if this component detects a fatal error
1053
        support.removePropertyChangeListener(listener);
1054
     *  that prevents this component from being used
1054
1055
     */
1055
    }
1056
    @Override
1056
1057
    protected synchronized void stopInternal() throws LifecycleException {
1057
1058
1058
    @Override
1059
        // Stop our thread
1059
    protected void initInternal() throws LifecycleException {
1060
        threadStop();
1060
        BlockingQueue<Runnable> startStopQueue =
1061
1061
            new LinkedBlockingQueue<Runnable>();
1062
        setState(LifecycleState.STOPPING);
1062
        startStopExecutor = new ThreadPoolExecutor(0,
1063
1063
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
1064
        // Stop the Valves in our pipeline (including the basic), if any
1064
                startStopQueue);
1065
        if (pipeline instanceof Lifecycle &&
1065
        super.initInternal();
1066
                ((Lifecycle) pipeline).getState().isAvailable()) {
1066
    }
1067
            ((Lifecycle) pipeline).stop();
1067
1068
        }
1068
1069
1069
    /**
1070
        // Stop our child containers, if any
1070
     * Start this component and implement the requirements
1071
        Container children[] = findChildren();
1071
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
1072
        for (int i = 0; i < children.length; i++) {
1072
     *
1073
            children[i].stop();
1073
     * @exception LifecycleException if this component detects a fatal error
1074
        }
1074
     *  that prevents this component from being used
1075
1075
     */
1076
        // Stop our subordinate components, if any
1076
    @Override
1077
        if ((resources != null) && (resources instanceof Lifecycle)) {
1077
    protected synchronized void startInternal() throws LifecycleException {
1078
            ((Lifecycle) resources).stop();
1078
1079
        }
1079
        // Start our subordinate components, if any
1080
        if ((realm != null) && (realm instanceof Lifecycle)) {
1080
        if ((loader != null) && (loader instanceof Lifecycle))
1081
            ((Lifecycle) realm).stop();
1081
            ((Lifecycle) loader).start();
1082
        }
1082
        logger = null;
1083
        if ((cluster != null) && (cluster instanceof Lifecycle)) {
1083
        getLogger();
1084
            ((Lifecycle) cluster).stop();
1084
        if ((logger != null) && (logger instanceof Lifecycle))
1085
        }
1085
            ((Lifecycle) logger).start();
1086
        if ((manager != null) && (manager instanceof Lifecycle) &&
1086
        if ((manager != null) && (manager instanceof Lifecycle))
1087
                ((Lifecycle) manager).getState().isAvailable() ) {
1087
            ((Lifecycle) manager).start();
1088
            ((Lifecycle) manager).stop();
1088
        if ((cluster != null) && (cluster instanceof Lifecycle))
1089
        }
1089
            ((Lifecycle) cluster).start();
1090
        if ((logger != null) && (logger instanceof Lifecycle)) {
1090
        if ((realm != null) && (realm instanceof Lifecycle))
1091
            ((Lifecycle) logger).stop();
1091
            ((Lifecycle) realm).start();
1092
        }
1092
        if ((resources != null) && (resources instanceof Lifecycle))
1093
        if ((loader != null) && (loader instanceof Lifecycle)) {
1093
            ((Lifecycle) resources).start();
1094
            ((Lifecycle) loader).stop();
1094
1095
        }
1095
        // Start our child containers, if any
1096
    }
1096
        Container children[] = findChildren();
1097
1097
        List<Future<Void>> results = new ArrayList<Future<Void>>();
1098
    @Override
1098
        for (int i = 0; i < children.length; i++) {
1099
    protected void destroyInternal() throws LifecycleException {
1099
            results.add(startStopExecutor.submit(new StartChild(children[i])));
1100
1100
        }
1101
        // Stop the Valves in our pipeline (including the basic), if any
1101
1102
        if (pipeline instanceof Lifecycle) {
1102
        boolean fail = false;
1103
            ((Lifecycle) pipeline).destroy();
1103
        for (Future<Void> result : results) {
1104
        }
1104
            try {
1105
1105
                result.get();
1106
        // Remove children now this container is being destroyed
1106
            } catch (Exception e) {
1107
        for (Container child : findChildren()) {
1107
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
1108
            removeChild(child);
1108
                fail = true;
1109
        }
1109
            }
1110
1110
            
1111
        // Required if the child is destroyed directly.
1111
        }
1112
        if (parent != null) {
1112
        if (fail) {
1113
            parent.removeChild(this);
1113
            throw new LifecycleException(
1114
        }
1114
                    sm.getString("containerBase.threadedStartFailed"));
1115
1115
        }
1116
        super.destroyInternal();
1116
1117
    }
1117
        // Start the Valves in our pipeline (including the basic), if any
1118
1118
        if (pipeline instanceof Lifecycle)
1119
    
1119
            ((Lifecycle) pipeline).start();
1120
    /**
1120
1121
     * Check this container for an access log and if none is found, look to the
1121
1122
     * parent. If there is no parent and still none is found, use the NoOp
1122
        setState(LifecycleState.STARTING);
1123
     * access log.
1123
1124
     */
1124
        // Start our thread
1125
    @Override
1125
        threadStart();
1126
    public void logAccess(Request request, Response response, long time,
1126
1127
            boolean useDefault) {
1127
    }
1128
        
1128
1129
        boolean logged = false;
1129
1130
        
1130
    /**
1131
        if (getAccessLog() != null) {
1131
     * Stop this component and implement the requirements
1132
            getAccessLog().log(request, response, time);
1132
     * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
1133
            logged = true;
1133
     *
1134
        }
1134
     * @exception LifecycleException if this component detects a fatal error
1135
        
1135
     *  that prevents this component from being used
1136
        if (getParent() != null) {
1136
     */
1137
            // No need to use default logger once request/response has been logged
1137
    @Override
1138
            // once
1138
    protected synchronized void stopInternal() throws LifecycleException {
1139
            getParent().logAccess(request, response, time, (useDefault && !logged));
1139
1140
        }
1140
        // Stop our thread
1141
    }
1141
        threadStop();
1142
1142
1143
    @Override
1143
        setState(LifecycleState.STOPPING);
1144
    public AccessLog getAccessLog() {
1144
1145
        
1145
        // Stop the Valves in our pipeline (including the basic), if any
1146
        if (accessLogScanComplete) {
1146
        if (pipeline instanceof Lifecycle &&
1147
            return accessLog;
1147
                ((Lifecycle) pipeline).getState().isAvailable()) {
1148
        }
1148
            ((Lifecycle) pipeline).stop();
1149
1149
        }
1150
        AccessLogAdapter adapter = null;
1150
1151
        Valve valves[] = getPipeline().getValves();
1151
        // Stop our child containers, if any
1152
        for (Valve valve : valves) {
1152
        Container children[] = findChildren();
1153
            if (valve instanceof AccessLog) {
1153
        List<Future<Void>> results = new ArrayList<Future<Void>>();
1154
                if (adapter == null) {
1154
        for (int i = 0; i < children.length; i++) {
1155
                    adapter = new AccessLogAdapter((AccessLog) valve);
1155
            results.add(startStopExecutor.submit(new StopChild(children[i])));
1156
                } else {
1156
        }
1157
                    adapter.add((AccessLog) valve);
1157
        
1158
                }
1158
        boolean fail = false;
1159
            }
1159
        for (Future<Void> result : results) {
1160
        }
1160
            try {
1161
        if (adapter != null) {
1161
                result.get();
1162
            accessLog = adapter;
1162
            } catch (Exception e) {
1163
        }
1163
                log.error(sm.getString("containerBase.threadedStopFailed"), e);
1164
        accessLogScanComplete = true;
1164
                fail = true;
1165
        return accessLog;
1165
            }
1166
    }
1166
        }
1167
1167
        if (fail) {
1168
    // ------------------------------------------------------- Pipeline Methods
1168
            throw new LifecycleException(
1169
1169
                    sm.getString("containerBase.threadedStopFailed"));
1170
1170
        }
1171
    /**
1171
1172
     * Convenience method, intended for use by the digester to simplify the
1172
        // Stop our subordinate components, if any
1173
     * process of adding Valves to containers. See
1173
        if ((resources != null) && (resources instanceof Lifecycle)) {
1174
     * {@link Pipeline#addValve(Valve)} for full details. Components other than
1174
            ((Lifecycle) resources).stop();
1175
     * the digester should use {@link #getPipeline()}.{@link #addValve(Valve)} in case a
1175
        }
1176
     * future implementation provides an alternative method for the digester to
1176
        if ((realm != null) && (realm instanceof Lifecycle)) {
1177
     * use.
1177
            ((Lifecycle) realm).stop();
1178
     *
1178
        }
1179
     * @param valve Valve to be added
1179
        if ((cluster != null) && (cluster instanceof Lifecycle)) {
1180
     *
1180
            ((Lifecycle) cluster).stop();
1181
     * @exception IllegalArgumentException if this Container refused to
1181
        }
1182
     *  accept the specified Valve
1182
        if ((manager != null) && (manager instanceof Lifecycle) &&
1183
     * @exception IllegalArgumentException if the specified Valve refuses to be
1183
                ((Lifecycle) manager).getState().isAvailable() ) {
1184
     *  associated with this Container
1184
            ((Lifecycle) manager).stop();
1185
     * @exception IllegalStateException if the specified Valve is already
1185
        }
1186
     *  associated with a different Container
1186
        if ((logger != null) && (logger instanceof Lifecycle)) {
1187
     */
1187
            ((Lifecycle) logger).stop();
1188
    public synchronized void addValve(Valve valve) {
1188
        }
1189
1189
        if ((loader != null) && (loader instanceof Lifecycle)) {
1190
        pipeline.addValve(valve);
1190
            ((Lifecycle) loader).stop();
1191
    }
1191
        }
1192
1192
    }
1193
1193
1194
    /**
1194
    @Override
1195
     * Execute a periodic task, such as reloading, etc. This method will be
1195
    protected void destroyInternal() throws LifecycleException {
1196
     * invoked inside the classloading context of this container. Unexpected
1196
1197
     * throwables will be caught and logged.
1197
        // Stop the Valves in our pipeline (including the basic), if any
1198
     */
1198
        if (pipeline instanceof Lifecycle) {
1199
    @Override
1199
            ((Lifecycle) pipeline).destroy();
1200
    public void backgroundProcess() {
1200
        }
1201
        
1201
1202
        if (!getState().isAvailable())
1202
        // Remove children now this container is being destroyed
1203
            return;
1203
        for (Container child : findChildren()) {
1204
1204
            removeChild(child);
1205
        if (cluster != null) {
1205
        }
1206
            try {
1206
1207
                cluster.backgroundProcess();
1207
        // Required if the child is destroyed directly.
1208
            } catch (Exception e) {
1208
        if (parent != null) {
1209
                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
1209
            parent.removeChild(this);
1210
            }
1210
        }
1211
        }
1211
1212
        if (loader != null) {
1212
        startStopExecutor.shutdownNow();
1213
            try {
1213
1214
                loader.backgroundProcess();
1214
        super.destroyInternal();
1215
            } catch (Exception e) {
1215
    }
1216
                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
1216
1217
            }
1217
    
1218
        }
1218
    /**
1219
        if (manager != null) {
1219
     * Check this container for an access log and if none is found, look to the
1220
            try {
1220
     * parent. If there is no parent and still none is found, use the NoOp
1221
                manager.backgroundProcess();
1221
     * access log.
1222
            } catch (Exception e) {
1222
     */
1223
                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
1223
    @Override
1224
            }
1224
    public void logAccess(Request request, Response response, long time,
1225
        }
1225
            boolean useDefault) {
1226
        if (realm != null) {
1226
        
1227
            try {
1227
        boolean logged = false;
1228
                realm.backgroundProcess();
1228
        
1229
            } catch (Exception e) {
1229
        if (getAccessLog() != null) {
1230
                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
1230
            getAccessLog().log(request, response, time);
1231
            }
1231
            logged = true;
1232
        }
1232
        }
1233
        Valve current = pipeline.getFirst();
1233
        
1234
        while (current != null) {
1234
        if (getParent() != null) {
1235
            try {
1235
            // No need to use default logger once request/response has been logged
1236
                current.backgroundProcess();
1236
            // once
1237
            } catch (Exception e) {
1237
            getParent().logAccess(request, response, time, (useDefault && !logged));
1238
                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
1238
        }
1239
            }
1239
    }
1240
            current = current.getNext();
1240
1241
        }
1241
    @Override
1242
        fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
1242
    public AccessLog getAccessLog() {
1243
    }
1243
        
1244
1244
        if (accessLogScanComplete) {
1245
1245
            return accessLog;
1246
    // ------------------------------------------------------ Protected Methods
1246
        }
1247
1247
1248
1248
        AccessLogAdapter adapter = null;
1249
    /**
1249
        Valve valves[] = getPipeline().getValves();
1250
     * Notify all container event listeners that a particular event has
1250
        for (Valve valve : valves) {
1251
     * occurred for this Container.  The default implementation performs
1251
            if (valve instanceof AccessLog) {
1252
     * this notification synchronously using the calling thread.
1252
                if (adapter == null) {
1253
     *
1253
                    adapter = new AccessLogAdapter((AccessLog) valve);
1254
     * @param type Event type
1254
                } else {
1255
     * @param data Event data
1255
                    adapter.add((AccessLog) valve);
1256
     */
1256
                }
1257
    @Override
1257
            }
1258
    public void fireContainerEvent(String type, Object data) {
1258
        }
1259
1259
        if (adapter != null) {
1260
        if (listeners.size() < 1)
1260
            accessLog = adapter;
1261
            return;
1261
        }
1262
        ContainerEvent event = new ContainerEvent(this, type, data);
1262
        accessLogScanComplete = true;
1263
        ContainerListener list[] = new ContainerListener[0];
1263
        return accessLog;
1264
        synchronized (listeners) {
1264
    }
1265
            list = listeners.toArray(list);
1265
1266
        }
1266
    // ------------------------------------------------------- Pipeline Methods
1267
        for (int i = 0; i < list.length; i++)
1267
1268
            list[i].containerEvent(event);
1268
1269
1269
    /**
1270
    }
1270
     * Convenience method, intended for use by the digester to simplify the
1271
1271
     * process of adding Valves to containers. See
1272
1272
     * {@link Pipeline#addValve(Valve)} for full details. Components other than
1273
    /**
1273
     * the digester should use {@link #getPipeline()}.{@link #addValve(Valve)} in case a
1274
     * Return the abbreviated name of this container for logging messages
1274
     * future implementation provides an alternative method for the digester to
1275
     */
1275
     * use.
1276
    protected String logName() {
1276
     *
1277
1277
     * @param valve Valve to be added
1278
        if (logName != null) {
1278
     *
1279
            return logName;
1279
     * @exception IllegalArgumentException if this Container refused to
1280
        }
1280
     *  accept the specified Valve
1281
        String loggerName = null;
1281
     * @exception IllegalArgumentException if the specified Valve refuses to be
1282
        Container current = this;
1282
     *  associated with this Container
1283
        while (current != null) {
1283
     * @exception IllegalStateException if the specified Valve is already
1284
            String name = current.getName();
1284
     *  associated with a different Container
1285
            if ((name == null) || (name.equals(""))) {
1285
     */
1286
                name = "/";
1286
    public synchronized void addValve(Valve valve) {
1287
            } else if (name.startsWith("##")) {
1287
1288
                name = "/" + name;
1288
        pipeline.addValve(valve);
1289
            }
1289
    }
1290
            loggerName = "[" + name + "]" 
1290
1291
                + ((loggerName != null) ? ("." + loggerName) : "");
1291
1292
            current = current.getParent();
1292
    /**
1293
        }
1293
     * Execute a periodic task, such as reloading, etc. This method will be
1294
        logName = ContainerBase.class.getName() + "." + loggerName;
1294
     * invoked inside the classloading context of this container. Unexpected
1295
        return logName;
1295
     * throwables will be caught and logged.
1296
        
1296
     */
1297
    }
1297
    @Override
1298
1298
    public void backgroundProcess() {
1299
    
1299
        
1300
    // -------------------- JMX and Registration  --------------------
1300
        if (!getState().isAvailable())
1301
1301
            return;
1302
    @Override
1302
1303
    protected String getDomainInternal() {
1303
        if (cluster != null) {
1304
        return MBeanUtils.getDomain(this);
1304
            try {
1305
    }
1305
                cluster.backgroundProcess();
1306
1306
            } catch (Exception e) {
1307
    public ObjectName[] getChildren() {
1307
                log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e);                
1308
        ObjectName result[]=new ObjectName[children.size()];
1308
            }
1309
        Iterator<Container> it=children.values().iterator();
1309
        }
1310
        int i=0;
1310
        if (loader != null) {
1311
        while( it.hasNext() ) {
1311
            try {
1312
            Object next=it.next();
1312
                loader.backgroundProcess();
1313
            if( next instanceof ContainerBase ) {
1313
            } catch (Exception e) {
1314
                result[i++]=((ContainerBase)next).getObjectName();
1314
                log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e);                
1315
            }
1315
            }
1316
        }
1316
        }
1317
        return result;
1317
        if (manager != null) {
1318
    }
1318
            try {
1319
1319
                manager.backgroundProcess();
1320
    
1320
            } catch (Exception e) {
1321
    // -------------------- Background Thread --------------------
1321
                log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e);                
1322
1322
            }
1323
    /**
1323
        }
1324
     * Start the background thread that will periodically check for
1324
        if (realm != null) {
1325
     * session timeouts.
1325
            try {
1326
     */
1326
                realm.backgroundProcess();
1327
    protected void threadStart() {
1327
            } catch (Exception e) {
1328
1328
                log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e);                
1329
        if (thread != null)
1329
            }
1330
            return;
1330
        }
1331
        if (backgroundProcessorDelay <= 0)
1331
        Valve current = pipeline.getFirst();
1332
            return;
1332
        while (current != null) {
1333
1333
            try {
1334
        threadDone = false;
1334
                current.backgroundProcess();
1335
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
1335
            } catch (Exception e) {
1336
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
1336
                log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e);                
1337
        thread.setDaemon(true);
1337
            }
1338
        thread.start();
1338
            current = current.getNext();
1339
1339
        }
1340
    }
1340
        fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
1341
1341
    }
1342
1342
1343
    /**
1343
1344
     * Stop the background thread that is periodically checking for
1344
    // ------------------------------------------------------ Protected Methods
1345
     * session timeouts.
1345
1346
     */
1346
1347
    protected void threadStop() {
1347
    /**
1348
1348
     * Notify all container event listeners that a particular event has
1349
        if (thread == null)
1349
     * occurred for this Container.  The default implementation performs
1350
            return;
1350
     * this notification synchronously using the calling thread.
1351
1351
     *
1352
        threadDone = true;
1352
     * @param type Event type
1353
        thread.interrupt();
1353
     * @param data Event data
1354
        try {
1354
     */
1355
            thread.join();
1355
    @Override
1356
        } catch (InterruptedException e) {
1356
    public void fireContainerEvent(String type, Object data) {
1357
            // Ignore
1357
1358
        }
1358
        if (listeners.size() < 1)
1359
1359
            return;
1360
        thread = null;
1360
        ContainerEvent event = new ContainerEvent(this, type, data);
1361
1361
        ContainerListener list[] = new ContainerListener[0];
1362
    }
1362
        synchronized (listeners) {
1363
1363
            list = listeners.toArray(list);
1364
1364
        }
1365
    // -------------------------------------- ContainerExecuteDelay Inner Class
1365
        for (int i = 0; i < list.length; i++)
1366
1366
            list[i].containerEvent(event);
1367
1367
1368
    /**
1368
    }
1369
     * Private thread class to invoke the backgroundProcess method 
1369
1370
     * of this container and its children after a fixed delay.
1370
1371
     */
1371
    /**
1372
    protected class ContainerBackgroundProcessor implements Runnable {
1372
     * Return the abbreviated name of this container for logging messages
1373
1373
     */
1374
        @Override
1374
    protected String logName() {
1375
        public void run() {
1375
1376
            while (!threadDone) {
1376
        if (logName != null) {
1377
                try {
1377
            return logName;
1378
                    Thread.sleep(backgroundProcessorDelay * 1000L);
1378
        }
1379
                } catch (InterruptedException e) {
1379
        String loggerName = null;
1380
                    // Ignore
1380
        Container current = this;
1381
                }
1381
        while (current != null) {
1382
                if (!threadDone) {
1382
            String name = current.getName();
1383
                    Container parent = (Container) getMappingObject();
1383
            if ((name == null) || (name.equals(""))) {
1384
                    ClassLoader cl = 
1384
                name = "/";
1385
                        Thread.currentThread().getContextClassLoader();
1385
            } else if (name.startsWith("##")) {
1386
                    if (parent.getLoader() != null) {
1386
                name = "/" + name;
1387
                        cl = parent.getLoader().getClassLoader();
1387
            }
1388
                    }
1388
            loggerName = "[" + name + "]" 
1389
                    processChildren(parent, cl);
1389
                + ((loggerName != null) ? ("." + loggerName) : "");
1390
                }
1390
            current = current.getParent();
1391
            }
1391
        }
1392
        }
1392
        logName = ContainerBase.class.getName() + "." + loggerName;
1393
1393
        return logName;
1394
        protected void processChildren(Container container, ClassLoader cl) {
1394
        
1395
            try {
1395
    }
1396
                if (container.getLoader() != null) {
1396
1397
                    Thread.currentThread().setContextClassLoader
1397
    
1398
                        (container.getLoader().getClassLoader());
1398
    // -------------------- JMX and Registration  --------------------
1399
                }
1399
1400
                container.backgroundProcess();
1400
    @Override
1401
            } catch (Throwable t) {
1401
    protected String getDomainInternal() {
1402
                ExceptionUtils.handleThrowable(t);
1402
        return MBeanUtils.getDomain(this);
1403
                log.error("Exception invoking periodic operation: ", t);
1403
    }
1404
            } finally {
1404
1405
                Thread.currentThread().setContextClassLoader(cl);
1405
    public ObjectName[] getChildren() {
1406
            }
1406
        ObjectName result[]=new ObjectName[children.size()];
1407
            Container[] children = container.findChildren();
1407
        Iterator<Container> it=children.values().iterator();
1408
            for (int i = 0; i < children.length; i++) {
1408
        int i=0;
1409
                if (children[i].getBackgroundProcessorDelay() <= 0) {
1409
        while( it.hasNext() ) {
1410
                    processChildren(children[i], cl);
1410
            Object next=it.next();
1411
                }
1411
            if( next instanceof ContainerBase ) {
1412
            }
1412
                result[i++]=((ContainerBase)next).getObjectName();
1413
        }
1413
            }
1414
    }
1414
        }
1415
}
1415
        return result;
1416
    }
1417
1418
    
1419
    // -------------------- Background Thread --------------------
1420
1421
    /**
1422
     * Start the background thread that will periodically check for
1423
     * session timeouts.
1424
     */
1425
    protected void threadStart() {
1426
1427
        if (thread != null)
1428
            return;
1429
        if (backgroundProcessorDelay <= 0)
1430
            return;
1431
1432
        threadDone = false;
1433
        String threadName = "ContainerBackgroundProcessor[" + toString() + "]";
1434
        thread = new Thread(new ContainerBackgroundProcessor(), threadName);
1435
        thread.setDaemon(true);
1436
        thread.start();
1437
1438
    }
1439
1440
1441
    /**
1442
     * Stop the background thread that is periodically checking for
1443
     * session timeouts.
1444
     */
1445
    protected void threadStop() {
1446
1447
        if (thread == null)
1448
            return;
1449
1450
        threadDone = true;
1451
        thread.interrupt();
1452
        try {
1453
            thread.join();
1454
        } catch (InterruptedException e) {
1455
            // Ignore
1456
        }
1457
1458
        thread = null;
1459
1460
    }
1461
1462
1463
    // -------------------------------------- ContainerExecuteDelay Inner Class
1464
1465
1466
    /**
1467
     * Private thread class to invoke the backgroundProcess method 
1468
     * of this container and its children after a fixed delay.
1469
     */
1470
    protected class ContainerBackgroundProcessor implements Runnable {
1471
1472
        @Override
1473
        public void run() {
1474
            while (!threadDone) {
1475
                try {
1476
                    Thread.sleep(backgroundProcessorDelay * 1000L);
1477
                } catch (InterruptedException e) {
1478
                    // Ignore
1479
                }
1480
                if (!threadDone) {
1481
                    Container parent = (Container) getMappingObject();
1482
                    ClassLoader cl = 
1483
                        Thread.currentThread().getContextClassLoader();
1484
                    if (parent.getLoader() != null) {
1485
                        cl = parent.getLoader().getClassLoader();
1486
                    }
1487
                    processChildren(parent, cl);
1488
                }
1489
            }
1490
        }
1491
1492
        protected void processChildren(Container container, ClassLoader cl) {
1493
            try {
1494
                if (container.getLoader() != null) {
1495
                    Thread.currentThread().setContextClassLoader
1496
                        (container.getLoader().getClassLoader());
1497
                }
1498
                container.backgroundProcess();
1499
            } catch (Throwable t) {
1500
                ExceptionUtils.handleThrowable(t);
1501
                log.error("Exception invoking periodic operation: ", t);
1502
            } finally {
1503
                Thread.currentThread().setContextClassLoader(cl);
1504
            }
1505
            Container[] children = container.findChildren();
1506
            for (int i = 0; i < children.length; i++) {
1507
                if (children[i].getBackgroundProcessorDelay() <= 0) {
1508
                    processChildren(children[i], cl);
1509
                }
1510
            }
1511
        }
1512
    }
1513
    
1514
    
1515
    // ----------------------------- Inner classes used with start/stop Executor
1516
    
1517
    private static class StartChild implements Callable<Void> {
1518
1519
        private Container child;
1520
        
1521
        public StartChild(Container child) {
1522
            this.child = child;
1523
        }
1524
1525
        @Override
1526
        public Void call() throws LifecycleException {
1527
            child.start();
1528
            return null;
1529
        }
1530
    }
1531
1532
    private static class StopChild implements Callable<Void> {
1533
1534
        private Container child;
1535
        
1536
        public StopChild(Container child) {
1537
            this.child = child;
1538
        }
1539
1540
        @Override
1541
        public Void call() throws LifecycleException {
1542
            child.stop();
1543
            return null;
1544
        }
1545
    }
1546
}
(-)a/java/org/apache/catalina/core/LocalStrings.properties (-255 / +257 lines)
Lines 1-255 Link Here
1
# Licensed to the Apache Software Foundation (ASF) under one or more
1
# Licensed to the Apache Software Foundation (ASF) under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
6
# the License.  You may obtain a copy of the License at
7
#
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
9
#
10
# Unless required by applicable law or agreed to in writing, software
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
14
# limitations under the License.
15
15
16
applicationContext.addFilter.ise=Filters can not be added to context {0} as the context has been initialised
16
applicationContext.addFilter.ise=Filters can not be added to context {0} as the context has been initialised
17
applicationContext.addListener.iae.cnfe=Unable to create an instance of type [{0}]
17
applicationContext.addListener.iae.cnfe=Unable to create an instance of type [{0}]
18
applicationContext.addListener.iae.wrongType=The type specified [{0}] is not one of the expected listener types
18
applicationContext.addListener.iae.wrongType=The type specified [{0}] is not one of the expected listener types
19
applicationContext.addListener.iae.sclNotAllowed=Once the first ServletContextListener has been called, no more ServletContextListeners may be added.
19
applicationContext.addListener.iae.sclNotAllowed=Once the first ServletContextListener has been called, no more ServletContextListeners may be added.
20
applicationContext.addListener.ise=Listeners can not be added to context {0} as the context has been initialised
20
applicationContext.addListener.ise=Listeners can not be added to context {0} as the context has been initialised
21
applicationContext.addRole.ise=Roles can not be added to context {0} as the context has been initialised
21
applicationContext.addRole.ise=Roles can not be added to context {0} as the context has been initialised
22
applicationContext.addServlet.ise=Servlets can not be added to context {0} as the context has been initialised
22
applicationContext.addServlet.ise=Servlets can not be added to context {0} as the context has been initialised
23
applicationContext.attributeEvent=Exception thrown by attributes event listener
23
applicationContext.attributeEvent=Exception thrown by attributes event listener
24
applicationContext.mapping.error=Error during mapping
24
applicationContext.mapping.error=Error during mapping
25
applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character
25
applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character
26
applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character
26
applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character
27
applicationContext.role.iae=An individual role to declare for context [{0}] may not be null nor the empty string
27
applicationContext.role.iae=An individual role to declare for context [{0}] may not be null nor the empty string
28
applicationContext.roles.iae=Array of roles to declare for context [{0}] cannot be null
28
applicationContext.roles.iae=Array of roles to declare for context [{0}] cannot be null
29
applicationContext.setAttribute.namenull=Name cannot be null
29
applicationContext.setAttribute.namenull=Name cannot be null
30
applicationContext.addSessionCookieConfig.ise=Session Cookie configuration cannot be set for context {0} as the context has been initialised
30
applicationContext.addSessionCookieConfig.ise=Session Cookie configuration cannot be set for context {0} as the context has been initialised
31
applicationContext.setSessionTracking.ise=The session tracking modes for context {0} cannot be set whilst the context is running
31
applicationContext.setSessionTracking.ise=The session tracking modes for context {0} cannot be set whilst the context is running
32
applicationContext.setSessionTracking.iae.invalid=The session tracking mode {0} requested for context {1} is not supported by that context
32
applicationContext.setSessionTracking.iae.invalid=The session tracking mode {0} requested for context {1} is not supported by that context
33
applicationContext.setSessionTracking.iae.ssl=The session tracking modes requested for context {1} included SSL and at least one other mode. SSL may not be configured with other modes.
33
applicationContext.setSessionTracking.iae.ssl=The session tracking modes requested for context {1} included SSL and at least one other mode. SSL may not be configured with other modes.
34
applicationContext.lookup.error=Failed to locate resource [{0}] in context [{1}]
34
applicationContext.lookup.error=Failed to locate resource [{0}] in context [{1}]
35
applicationDispatcher.allocateException=Allocate exception for servlet {0}
35
applicationDispatcher.allocateException=Allocate exception for servlet {0}
36
applicationDispatcher.deallocateException=Deallocate exception for servlet {0}
36
applicationDispatcher.deallocateException=Deallocate exception for servlet {0}
37
applicationDispatcher.forward.ise=Cannot forward after response has been committed
37
applicationDispatcher.forward.ise=Cannot forward after response has been committed
38
applicationDispatcher.forward.throw=Forwarded resource threw an exception
38
applicationDispatcher.forward.throw=Forwarded resource threw an exception
39
applicationDispatcher.include.throw=Included resource threw an exception
39
applicationDispatcher.include.throw=Included resource threw an exception
40
applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable
40
applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable
41
applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception
41
applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception
42
applicationDispatcher.specViolation.request=Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1
42
applicationDispatcher.specViolation.request=Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1
43
applicationDispatcher.specViolation.response=Original SevletResponse or wrapped original ServletResponse not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1
43
applicationDispatcher.specViolation.response=Original SevletResponse or wrapped original ServletResponse not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1
44
applicationFilterConfig.jmxRegisterFail=JMX registration failed for filter of type [{0}] and name [{1}]
44
applicationFilterConfig.jmxRegisterFail=JMX registration failed for filter of type [{0}] and name [{1}]
45
applicationFilterConfig.jmxUnregister=JMX de-registration complete for filter of type [{0}] and name [{1}]
45
applicationFilterConfig.jmxUnregister=JMX de-registration complete for filter of type [{0}] and name [{1}]
46
applicationFilterConfig.jmxUnregisterFail=JMX de-registration failed for filter of type [{0}] and name [{1}]
46
applicationFilterConfig.jmxUnregisterFail=JMX de-registration failed for filter of type [{0}] and name [{1}]
47
applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}]
47
applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}]
48
applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}]
48
applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}]
49
applicationRequest.badParent=Cannot locate parent Request implementation
49
applicationRequest.badParent=Cannot locate parent Request implementation
50
applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper
50
applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper
51
applicationResponse.badParent=Cannot locate parent Response implementation
51
applicationResponse.badParent=Cannot locate parent Response implementation
52
applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper
52
applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper
53
applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}]
53
applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}]
54
applicationServletRegistration.setServletSecurity.ise=Security constraints can't be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised
54
applicationServletRegistration.setServletSecurity.ise=Security constraints can't be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised
55
aprListener.aprInit=The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0}
55
aprListener.aprInit=The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0}
56
aprListener.tcnInvalid=An incompatible version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat requires version {1} 
56
aprListener.tcnInvalid=An incompatible version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat requires version {1} 
57
aprListener.tcnVersion=An older version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of {1}
57
aprListener.tcnVersion=An older version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of {1}
58
aprListener.aprDestroy=Failed shutdown of APR based Apache Tomcat Native library
58
aprListener.aprDestroy=Failed shutdown of APR based Apache Tomcat Native library
59
aprListener.sslInit=Failed to initialize the SSLEngine.
59
aprListener.sslInit=Failed to initialize the SSLEngine.
60
aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0}.
60
aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0}.
61
aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}].
61
aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}].
62
asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing.
62
asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing.
63
containerBase.alreadyStarted=Container {0} has already been started
63
containerBase.alreadyStarted=Container {0} has already been started
64
containerBase.notConfigured=No basic Valve has been configured
64
containerBase.notConfigured=No basic Valve has been configured
65
containerBase.notStarted=Container {0} has not been started
65
containerBase.notStarted=Container {0} has not been started
66
containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process
66
containerBase.threadedStartFailed=A child container failed during start
67
containerBase.backgroundProcess.loader=Exception processing loader {0} background process
67
containerBase.threadedStopFailed=A child container failed during stop
68
containerBase.backgroundProcess.manager=Exception processing manager {0} background process
68
containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process
69
containerBase.backgroundProcess.realm=Exception processing realm {0} background process
69
containerBase.backgroundProcess.loader=Exception processing loader {0} background process
70
containerBase.backgroundProcess.valve=Exception processing valve {0} background process
70
containerBase.backgroundProcess.manager=Exception processing manager {0} background process
71
fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started
71
containerBase.backgroundProcess.realm=Exception processing realm {0} background process
72
fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started
72
containerBase.backgroundProcess.valve=Exception processing valve {0} background process
73
filterChain.filter=Filter execution threw an exception
73
fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started
74
filterChain.servlet=Servlet execution threw an exception
74
fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started
75
httpContextMapper.container=This container is not a StandardContext
75
filterChain.filter=Filter execution threw an exception
76
httpEngineMapper.container=This container is not a StandardEngine
76
filterChain.servlet=Servlet execution threw an exception
77
httpHostMapper.container=This container is not a StandardHost
77
httpContextMapper.container=This container is not a StandardContext
78
interceptorValve.alreadyStarted=InterceptorValve has already been started
78
httpEngineMapper.container=This container is not a StandardEngine
79
interceptorValve.notStarted=InterceptorValve has not yet been started
79
httpHostMapper.container=This container is not a StandardHost
80
jreLeakListener.keepAliveFail=Failed to trigger creation of the sun.net.www.http.HttpClient class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
80
interceptorValve.alreadyStarted=InterceptorValve has already been started
81
jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
81
interceptorValve.notStarted=InterceptorValve has not yet been started
82
jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default
82
jreLeakListener.keepAliveFail=Failed to trigger creation of the sun.net.www.http.HttpClient class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
83
jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing
83
jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
84
jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class
84
jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default
85
jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
85
jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing
86
jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks.
86
jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class
87
naming.wsdlFailed=Failed to find wsdl file: {0}
87
jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs.
88
naming.bindFailed=Failed to bind object: {0}
88
jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks.
89
naming.jmxRegistrationFailed=Failed to register in JMX: {0}
89
naming.wsdlFailed=Failed to find wsdl file: {0}
90
naming.unbindFailed=Failed to unbind object: {0}
90
naming.bindFailed=Failed to bind object: {0}
91
naming.invalidEnvEntryType=Environment entry {0} has an invalid type
91
naming.jmxRegistrationFailed=Failed to register in JMX: {0}
92
naming.invalidEnvEntryValue=Environment entry {0} has an invalid value
92
naming.unbindFailed=Failed to unbind object: {0}
93
naming.namingContextCreationFailed=Creation of the naming context failed: {0}
93
naming.invalidEnvEntryType=Environment entry {0} has an invalid type
94
standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper
94
naming.invalidEnvEntryValue=Environment entry {0} has an invalid value
95
standardContext.alreadyStarted=Context has already been started
95
naming.namingContextCreationFailed=Creation of the naming context failed: {0}
96
standardContext.applicationListener=Error configuring application listener of class {0}
96
standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper
97
standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s)
97
standardContext.alreadyStarted=Context has already been started
98
standardContext.badRequest=Invalid request path ({0}).
98
standardContext.applicationListener=Error configuring application listener of class {0}
99
standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}]
99
standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s)
100
standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched.
100
standardContext.badRequest=Invalid request path ({0}).
101
standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored.
101
standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}]
102
standardContext.errorPage.error=Error page location {0} must start with a ''/''
102
standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched.
103
standardContext.errorPage.required=ErrorPage cannot be null
103
standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored.
104
standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4
104
standardContext.errorPage.error=Error page location {0} must start with a ''/''
105
standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name>
105
standardContext.errorPage.required=ErrorPage cannot be null
106
standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0}
106
standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4
107
standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping
107
standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name>
108
standardContext.filterStart=Exception starting filter {0}
108
standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0}
109
standardContext.filterStartFailed=Failed to start application Filters successfully
109
standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping
110
standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0}
110
standardContext.filterStart=Exception starting filter {0}
111
standardContext.requestListener.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0}
111
standardContext.filterStartFailed=Failed to start application Filters successfully
112
standardContext.requestListenerStartFailed=Failed to start request listener valve successfully
112
standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0}
113
standardContext.requestListenerConfig.added=Added request listener Valve
113
standardContext.requestListener.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0}
114
standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0}
114
standardContext.requestListenerStartFailed=Failed to start request listener valve successfully
115
standardContext.isUnavailable=This application is not currently available
115
standardContext.requestListenerConfig.added=Added request listener Valve
116
standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0}
116
standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0}
117
standardContext.listenerStartFailed=Failed to start application Listeners successfully
117
standardContext.isUnavailable=This application is not currently available
118
standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0}
118
standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0}
119
standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/'
119
standardContext.listenerStartFailed=Failed to start application Listeners successfully
120
standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4
120
standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0}
121
standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/'
121
standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/'
122
standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4
122
standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4
123
standardContext.loginConfig.required=LoginConfig cannot be null
123
standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/'
124
standardContext.manager=Configured a manager of class [{0}]
124
standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4
125
standardContext.mappingError=MAPPING configuration error for relative URI {0}
125
standardContext.loginConfig.required=LoginConfig cannot be null
126
standardContext.namingResource.init.fail=Failed to init new naming resources
126
standardContext.manager=Configured a manager of class [{0}]
127
standardContext.namingResource.destroy.fail=Failed to destroy old naming resources
127
standardContext.mappingError=MAPPING configuration error for relative URI {0}
128
standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}]
128
standardContext.namingResource.init.fail=Failed to init new naming resources
129
standardContext.notFound=The requested resource ({0}) is not available.
129
standardContext.namingResource.destroy.fail=Failed to destroy old naming resources
130
standardContext.notReloadable=Reloading is disabled on this Context
130
standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}]
131
standardContext.notStarted=Context with name [{0}] has not yet been started
131
standardContext.notFound=The requested resource ({0}) is not available.
132
standardContext.notWrapper=Child of a Context must be a Wrapper
132
standardContext.notReloadable=Reloading is disabled on this Context
133
standardContext.parameter.duplicate=Duplicate context initialization parameter {0}
133
standardContext.notStarted=Context with name [{0}] has not yet been started
134
standardContext.parameter.required=Both parameter name and parameter value are required
134
standardContext.notWrapper=Child of a Context must be a Wrapper
135
standardContext.pathInvalid=A context path must either be an empty string or start with a ''/''. The path [{0}] does not meet these criteria and has been changed to [{1}] 
135
standardContext.parameter.duplicate=Duplicate context initialization parameter {0}
136
standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed
136
standardContext.parameter.required=Both parameter name and parameter value are required
137
standardContext.reloadingFailed=Reloading this Context failed due to previous errors
137
standardContext.pathInvalid=A context path must either be an empty string or start with a ''/''. The path [{0}] does not meet these criteria and has been changed to [{1}] 
138
standardContext.reloadingStarted=Reloading Context with name [{0}] has started
138
standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed
139
standardContext.resourcesStart=Error starting static Resources
139
standardContext.reloadingFailed=Reloading this Context failed due to previous errors
140
standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix <http-method> and <http-method-omission> in the same web resource collection
140
standardContext.reloadingStarted=Reloading Context with name [{0}] has started
141
standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint
141
standardContext.resourcesStart=Error starting static Resources
142
standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
142
standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix <http-method> and <http-method-omission> in the same web resource collection
143
standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping
143
standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint
144
standardContext.startCleanup=Exception during cleanup after start failed
144
standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0}
145
standardContext.startFailed=Context [{0}] startup failed due to previous errors
145
standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping
146
standardContext.startingContext=Exception starting Context with name [{0}]
146
standardContext.startCleanup=Exception during cleanup after start failed
147
standardContext.startingLoader=Exception starting Loader
147
standardContext.startFailed=Context [{0}] startup failed due to previous errors
148
standardContext.startingManager=Exception starting Manager
148
standardContext.startingContext=Exception starting Context with name [{0}]
149
standardContext.startingWrapper=Exception starting Wrapper for servlet {0}
149
standardContext.startingLoader=Exception starting Loader
150
standardContext.stoppingContext=Exception stopping Context with name [{0}]
150
standardContext.startingManager=Exception starting Manager
151
standardContext.stoppingLoader=Exception stopping Loader
151
standardContext.startingWrapper=Exception starting Wrapper for servlet {0}
152
standardContext.stoppingManager=Exception stopping Manager
152
standardContext.stoppingContext=Exception stopping Context with name [{0}]
153
standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0}
153
standardContext.stoppingLoader=Exception stopping Loader
154
standardContext.urlDecode=Cannot URL decode request path {0}
154
standardContext.stoppingManager=Exception stopping Manager
155
standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4
155
standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0}
156
standardContext.urlValidate=Cannot validate URL decoded request path {0}
156
standardContext.urlDecode=Cannot URL decode request path {0}
157
standardContext.workPath=Exception obtaining work path for context [{0}]
157
standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4
158
standardContext.workCreateException=Failed to determine absolute work directory from directory [{0}] and CATALINA_HOME [{1}] for context [{2}]
158
standardContext.urlValidate=Cannot validate URL decoded request path {0}
159
standardContext.workCreateFail=Failed to create work directory [{0}] for context [{1}]
159
standardContext.workPath=Exception obtaining work path for context [{0}]
160
standardContextValve.acknowledgeException=Failed to acknowledge request with a 100 (Continue) response
160
standardContext.workCreateException=Failed to determine absolute work directory from directory [{0}] and CATALINA_HOME [{1}] for context [{2}]
161
standardEngine.alreadyStarted=Engine has already been started
161
standardContext.workCreateFail=Failed to create work directory [{0}] for context [{1}]
162
standardEngine.jvmRouteFail=Failed to set Engine's jvmRoute attribute from system property
162
standardContextValve.acknowledgeException=Failed to acknowledge request with a 100 (Continue) response
163
standardEngine.mappingError=MAPPING configuration error for server name {0}
163
standardEngine.alreadyStarted=Engine has already been started
164
standardEngine.noHost=No Host matches server name {0}
164
standardEngine.jvmRouteFail=Failed to set Engine's jvmRoute attribute from system property
165
standardEngine.noHostHeader=HTTP/1.1 request with no Host: header
165
standardEngine.mappingError=MAPPING configuration error for server name {0}
166
standardEngine.notHost=Child of an Engine must be a Host
166
standardEngine.noHost=No Host matches server name {0}
167
standardEngine.notParent=Engine cannot have a parent Container
167
standardEngine.noHostHeader=HTTP/1.1 request with no Host: header
168
standardEngine.notStarted=Engine has not yet been started
168
standardEngine.notHost=Child of an Engine must be a Host
169
standardEngine.unfoundHost=Virtual host {0} not found
169
standardEngine.notParent=Engine cannot have a parent Container
170
standardEngine.unknownHost=No server host specified in this request
170
standardEngine.notStarted=Engine has not yet been started
171
standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0}
171
standardEngine.unfoundHost=Virtual host {0} not found
172
standardHost.accessBase=Cannot access document base directory {0}
172
standardEngine.unknownHost=No server host specified in this request
173
standardHost.alreadyStarted=Host has already been started
173
standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0}
174
standardHost.appBase=Application base directory {0} does not exist
174
standardHost.accessBase=Cannot access document base directory {0}
175
standardHost.clientAbort=Remote Client Aborted Request, IOException: {0}
175
standardHost.alreadyStarted=Host has already been started
176
standardHost.configRequired=URL to configuration file is required
176
standardHost.appBase=Application base directory {0} does not exist
177
standardHost.configNotAllowed=Use of configuration file is not allowed
177
standardHost.clientAbort=Remote Client Aborted Request, IOException: {0}
178
standardHost.installBase=Only web applications in the Host web application directory can be installed
178
standardHost.configRequired=URL to configuration file is required
179
standardHost.installing=Installing web application at context path {0} from URL {1}
179
standardHost.configNotAllowed=Use of configuration file is not allowed
180
standardHost.installingWAR=Installing web application from URL {0}
180
standardHost.installBase=Only web applications in the Host web application directory can be installed
181
standardHost.installingXML=Processing Context configuration file URL {0}
181
standardHost.installing=Installing web application at context path {0} from URL {1}
182
standardHost.installError=Error deploying application at context path {0}
182
standardHost.installingWAR=Installing web application from URL {0}
183
standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0}
183
standardHost.installingXML=Processing Context configuration file URL {0}
184
standardHost.docBase=Document base directory {0} already exists
184
standardHost.installError=Error deploying application at context path {0}
185
standardHost.mappingError=MAPPING configuration error for request URI {0}
185
standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0}
186
standardHost.noContext=No Context configured to process this request
186
standardHost.docBase=Document base directory {0} already exists
187
standardHost.noHost=No Host configured to process this request
187
standardHost.mappingError=MAPPING configuration error for request URI {0}
188
standardHost.notContext=Child of a Host must be a Context
188
standardHost.noContext=No Context configured to process this request
189
standardHost.notStarted=Host has not yet been started
189
standardHost.noHost=No Host configured to process this request
190
standardHost.nullName=Host name is required
190
standardHost.notContext=Child of a Host must be a Context
191
standardHost.pathFormat=Invalid context path: {0}
191
standardHost.notStarted=Host has not yet been started
192
standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1}
192
standardHost.nullName=Host name is required
193
standardHost.pathMissing=Context path {0} is not currently in use
193
standardHost.pathFormat=Invalid context path: {0}
194
standardHost.pathRequired=Context path is required
194
standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1}
195
standardHost.pathUsed=Context path {0} is already in use
195
standardHost.pathMissing=Context path {0} is not currently in use
196
standardHost.removing=Removing web application at context path {0}
196
standardHost.pathRequired=Context path is required
197
standardHost.removeError=Error removing application at context path {0}
197
standardHost.pathUsed=Context path {0} is already in use
198
standardHost.start=Starting web application at context path {0}
198
standardHost.removing=Removing web application at context path {0}
199
standardHost.stop=Stopping web application at context path {0}
199
standardHost.removeError=Error removing application at context path {0}
200
standardHost.unfoundContext=Cannot find context for request URI {0}
200
standardHost.start=Starting web application at context path {0}
201
standardHost.warRequired=URL to web application archive is required
201
standardHost.stop=Stopping web application at context path {0}
202
standardHost.warURL=Invalid URL for web application archive: {0}
202
standardHost.unfoundContext=Cannot find context for request URI {0}
203
standardServer.onameFail=MBean name specified for Server [{0}] is not valid
203
standardHost.warRequired=URL to web application archive is required
204
standardServer.shutdownViaPort=A valid shutdown command was received via the shutdown port. Stopping the Server instance.
204
standardHost.warURL=Invalid URL for web application archive: {0}
205
standardService.connector.initFailed=Failed to initialize connector [{0}]
205
standardServer.onameFail=MBean name specified for Server [{0}] is not valid
206
standardService.connector.destroyFailed=Failed to destroy connector [{0}]
206
standardServer.shutdownViaPort=A valid shutdown command was received via the shutdown port. Stopping the Server instance.
207
standardService.connector.pauseFailed=Failed to pause connector [{0}]
207
standardService.connector.initFailed=Failed to initialize connector [{0}]
208
standardService.connector.startFailed=Failed to start connector [{0}]
208
standardService.connector.destroyFailed=Failed to destroy connector [{0}]
209
standardService.connector.stopFailed=Failed to stop connector [{0}]
209
standardService.connector.pauseFailed=Failed to pause connector [{0}]
210
standardService.initialize.failed=Service initializing at {0} failed
210
standardService.connector.startFailed=Failed to start connector [{0}]
211
standardService.onameFail=MBean name specified for Service [{0}] is not valid
211
standardService.connector.stopFailed=Failed to stop connector [{0}]
212
standardService.register.failed=Error registering Service at domain {0}
212
standardService.initialize.failed=Service initializing at {0} failed
213
standardService.start.name=Starting service {0}
213
standardService.onameFail=MBean name specified for Service [{0}] is not valid
214
standardService.stop.name=Stopping service {0}
214
standardService.register.failed=Error registering Service at domain {0}
215
standardThreadExecutor.onameFail=MBean name specified for Thread Executor [{0}] is not valid
215
standardService.start.name=Starting service {0}
216
standardWrapper.allocate=Error allocating a servlet instance
216
standardService.stop.name=Stopping service {0}
217
standardWrapper.allocateException=Allocate exception for servlet {0}
217
standardThreadExecutor.onameFail=MBean name specified for Thread Executor [{0}] is not valid
218
standardWrapper.containerServlet=Loading container servlet {0}
218
standardWrapper.allocate=Error allocating a servlet instance
219
standardWrapper.createFilters=Create filters exception for servlet {0}
219
standardWrapper.allocateException=Allocate exception for servlet {0}
220
standardWrapper.deallocateException=Deallocate exception for servlet {0}
220
standardWrapper.containerServlet=Loading container servlet {0}
221
standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception
221
standardWrapper.createFilters=Create filters exception for servlet {0}
222
standardWrapper.exception0=Tomcat Exception Report
222
standardWrapper.deallocateException=Deallocate exception for servlet {0}
223
standardWrapper.exception1=A Servlet Exception Has Occurred
223
standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception
224
standardWrapper.exception2=Exception Report:
224
standardWrapper.exception0=Tomcat Exception Report
225
standardWrapper.exception3=Root Cause:
225
standardWrapper.exception1=A Servlet Exception Has Occurred
226
standardWrapper.initException=Servlet.init() for servlet {0} threw exception
226
standardWrapper.exception2=Exception Report:
227
standardWrapper.instantiate=Error instantiating servlet class {0}
227
standardWrapper.exception3=Root Cause:
228
standardWrapper.isUnavailable=Servlet {0} is currently unavailable
228
standardWrapper.initException=Servlet.init() for servlet {0} threw exception
229
standardWrapper.jasperLoader=Using Jasper classloader for servlet {0}
229
standardWrapper.instantiate=Error instantiating servlet class {0}
230
standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character
230
standardWrapper.isUnavailable=Servlet {0} is currently unavailable
231
standardWrapper.loadException=Servlet {0} threw load() exception
231
standardWrapper.jasperLoader=Using Jasper classloader for servlet {0}
232
standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on
232
standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character
233
standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0}
233
standardWrapper.loadException=Servlet {0} threw load() exception
234
standardWrapper.notChild=Wrapper container may not have child containers
234
standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on
235
standardWrapper.notClass=No servlet class has been specified for servlet {0}
235
standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0}
236
standardWrapper.notContext=Parent container of a Wrapper must be a Context
236
standardWrapper.notChild=Wrapper container may not have child containers
237
standardWrapper.notFound=Servlet {0} is not available
237
standardWrapper.notClass=No servlet class has been specified for servlet {0}
238
standardWrapper.notServlet=Class {0} is not a Servlet
238
standardWrapper.notContext=Parent container of a Wrapper must be a Context
239
standardWrapper.releaseFilters=Release filters exception for servlet {0}
239
standardWrapper.notFound=Servlet {0} is not available
240
standardWrapper.serviceException=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception
240
standardWrapper.notServlet=Class {0} is not a Servlet
241
standardWrapper.serviceExceptionRoot=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception [{2}] with root cause
241
standardWrapper.releaseFilters=Release filters exception for servlet {0}
242
standardWrapper.statusHeader=HTTP Status {0} - {1}
242
standardWrapper.serviceException=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception
243
standardWrapper.statusTitle=Tomcat Error Report
243
standardWrapper.serviceExceptionRoot=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception [{2}] with root cause
244
standardWrapper.unavailable=Marking servlet {0} as unavailable
244
standardWrapper.statusHeader=HTTP Status {0} - {1}
245
standardWrapper.unloadException=Servlet {0} threw unload() exception
245
standardWrapper.statusTitle=Tomcat Error Report
246
standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded
246
standardWrapper.unavailable=Marking servlet {0} as unavailable
247
standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated
247
standardWrapper.unloadException=Servlet {0} threw unload() exception
248
threadLocalLeakPreventionListener.lifecycleEvent.error=Exception processing lifecycle event {0}
248
standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded
249
threadLocalLeakPreventionListener.containerEvent.error=Exception processing container event {0}
249
standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated
250
250
threadLocalLeakPreventionListener.lifecycleEvent.error=Exception processing lifecycle event {0}
251
defaultInstanceManager.restrictedServletsResource=Restricted servlets property file not found
251
threadLocalLeakPreventionListener.containerEvent.error=Exception processing container event {0}
252
defaultInstanceManager.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application
252
253
defaultInstanceManager.restrictedFiltersResource=Restricted filters property file not found
253
defaultInstanceManager.restrictedServletsResource=Restricted servlets property file not found
254
defaultInstanceManager.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application
254
defaultInstanceManager.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application
255
defaultInstanceManager.restrictedListenersResources="Restricted listeners property file not found
255
defaultInstanceManager.restrictedFiltersResource=Restricted filters property file not found
256
defaultInstanceManager.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application
257
defaultInstanceManager.restrictedListenersResources="Restricted listeners property file not found
(-)a/java/org/apache/catalina/core/StandardContext.java (-6544 / +6462 lines)
Lines 1-6544 Link Here
1
/*
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
3
 * contributor license agreements.  See the NOTICE file distributed with
3
 * contributor license agreements.  See the NOTICE file distributed with
4
 * this work for additional information regarding copyright ownership.
4
 * this work for additional information regarding copyright ownership.
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
5
 * The ASF licenses this file to You under the Apache License, Version 2.0
6
 * (the "License"); you may not use this file except in compliance with
6
 * (the "License"); you may not use this file except in compliance with
7
 * the License.  You may obtain a copy of the License at
7
 * the License.  You may obtain a copy of the License at
8
 * 
8
 * 
9
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *      http://www.apache.org/licenses/LICENSE-2.0
10
 * 
10
 * 
11
 * Unless required by applicable law or agreed to in writing, software
11
 * Unless required by applicable law or agreed to in writing, software
12
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * distributed under the License is distributed on an "AS IS" BASIS,
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 * See the License for the specific language governing permissions and
14
 * See the License for the specific language governing permissions and
15
 * limitations under the License.
15
 * limitations under the License.
16
 */
16
 */
17
17
18
18
19
package org.apache.catalina.core;
19
package org.apache.catalina.core;
20
20
21
import java.io.BufferedReader;
21
import java.io.BufferedReader;
22
import java.io.File;
22
import java.io.File;
23
import java.io.IOException;
23
import java.io.IOException;
24
import java.io.InputStream;
24
import java.io.InputStream;
25
import java.io.InputStreamReader;
25
import java.io.InputStreamReader;
26
import java.net.URL;
26
import java.net.URL;
27
import java.util.ArrayList;
27
import java.util.ArrayList;
28
import java.util.Arrays;
28
import java.util.Arrays;
29
import java.util.Collection;
29
import java.util.Collection;
30
import java.util.HashMap;
30
import java.util.HashMap;
31
import java.util.HashSet;
31
import java.util.HashSet;
32
import java.util.Hashtable;
32
import java.util.Hashtable;
33
import java.util.Iterator;
33
import java.util.Iterator;
34
import java.util.LinkedHashMap;
34
import java.util.LinkedHashMap;
35
import java.util.List;
35
import java.util.List;
36
import java.util.Map;
36
import java.util.Map;
37
import java.util.Set;
37
import java.util.Set;
38
import java.util.Stack;
38
import java.util.Stack;
39
import java.util.TreeMap;
39
import java.util.TreeMap;
40
import java.util.concurrent.Callable;
40
import java.util.concurrent.atomic.AtomicLong;
41
import java.util.concurrent.atomic.AtomicLong;
41
42
42
import javax.management.ListenerNotFoundException;
43
import javax.management.ListenerNotFoundException;
43
import javax.management.MBeanNotificationInfo;
44
import javax.management.MBeanNotificationInfo;
44
import javax.management.Notification;
45
import javax.management.Notification;
45
import javax.management.NotificationBroadcasterSupport;
46
import javax.management.NotificationBroadcasterSupport;
46
import javax.management.NotificationEmitter;
47
import javax.management.NotificationEmitter;
47
import javax.management.NotificationFilter;
48
import javax.management.NotificationFilter;
48
import javax.management.NotificationListener;
49
import javax.management.NotificationListener;
49
import javax.management.ObjectName;
50
import javax.management.ObjectName;
50
import javax.naming.NamingException;
51
import javax.naming.NamingException;
51
import javax.naming.directory.DirContext;
52
import javax.naming.directory.DirContext;
52
import javax.servlet.FilterConfig;
53
import javax.servlet.FilterConfig;
53
import javax.servlet.RequestDispatcher;
54
import javax.servlet.RequestDispatcher;
54
import javax.servlet.Servlet;
55
import javax.servlet.Servlet;
55
import javax.servlet.ServletContainerInitializer;
56
import javax.servlet.ServletContainerInitializer;
56
import javax.servlet.ServletContext;
57
import javax.servlet.ServletContext;
57
import javax.servlet.ServletContextAttributeListener;
58
import javax.servlet.ServletContextAttributeListener;
58
import javax.servlet.ServletContextEvent;
59
import javax.servlet.ServletContextEvent;
59
import javax.servlet.ServletContextListener;
60
import javax.servlet.ServletContextListener;
60
import javax.servlet.ServletException;
61
import javax.servlet.ServletException;
61
import javax.servlet.ServletRegistration;
62
import javax.servlet.ServletRegistration;
62
import javax.servlet.ServletRequest;
63
import javax.servlet.ServletRequest;
63
import javax.servlet.ServletRequestAttributeListener;
64
import javax.servlet.ServletRequestAttributeListener;
64
import javax.servlet.ServletRequestEvent;
65
import javax.servlet.ServletRequestEvent;
65
import javax.servlet.ServletRequestListener;
66
import javax.servlet.ServletRequestListener;
66
import javax.servlet.ServletSecurityElement;
67
import javax.servlet.ServletSecurityElement;
67
import javax.servlet.descriptor.JspConfigDescriptor;
68
import javax.servlet.descriptor.JspConfigDescriptor;
68
import javax.servlet.http.HttpSessionAttributeListener;
69
import javax.servlet.http.HttpSessionAttributeListener;
69
import javax.servlet.http.HttpSessionListener;
70
import javax.servlet.http.HttpSessionListener;
70
71
71
import org.apache.catalina.Authenticator;
72
import org.apache.catalina.Authenticator;
72
import org.apache.catalina.Container;
73
import org.apache.catalina.Container;
73
import org.apache.catalina.ContainerListener;
74
import org.apache.catalina.ContainerListener;
74
import org.apache.catalina.Context;
75
import org.apache.catalina.Context;
75
import org.apache.catalina.Globals;
76
import org.apache.catalina.Globals;
76
import org.apache.catalina.Host;
77
import org.apache.catalina.Host;
77
import org.apache.catalina.InstanceListener;
78
import org.apache.catalina.InstanceListener;
78
import org.apache.catalina.Lifecycle;
79
import org.apache.catalina.Lifecycle;
79
import org.apache.catalina.LifecycleException;
80
import org.apache.catalina.LifecycleException;
80
import org.apache.catalina.LifecycleListener;
81
import org.apache.catalina.LifecycleListener;
81
import org.apache.catalina.LifecycleState;
82
import org.apache.catalina.LifecycleState;
82
import org.apache.catalina.Loader;
83
import org.apache.catalina.Loader;
83
import org.apache.catalina.Manager;
84
import org.apache.catalina.Manager;
84
import org.apache.catalina.Pipeline;
85
import org.apache.catalina.Pipeline;
85
import org.apache.catalina.Valve;
86
import org.apache.catalina.Valve;
86
import org.apache.catalina.Wrapper;
87
import org.apache.catalina.Wrapper;
87
import org.apache.catalina.deploy.ApplicationParameter;
88
import org.apache.catalina.deploy.ApplicationParameter;
88
import org.apache.catalina.deploy.ErrorPage;
89
import org.apache.catalina.deploy.ErrorPage;
89
import org.apache.catalina.deploy.FilterDef;
90
import org.apache.catalina.deploy.FilterDef;
90
import org.apache.catalina.deploy.FilterMap;
91
import org.apache.catalina.deploy.FilterMap;
91
import org.apache.catalina.deploy.Injectable;
92
import org.apache.catalina.deploy.Injectable;
92
import org.apache.catalina.deploy.InjectionTarget;
93
import org.apache.catalina.deploy.InjectionTarget;
93
import org.apache.catalina.deploy.LoginConfig;
94
import org.apache.catalina.deploy.LoginConfig;
94
import org.apache.catalina.deploy.MessageDestination;
95
import org.apache.catalina.deploy.MessageDestination;
95
import org.apache.catalina.deploy.MessageDestinationRef;
96
import org.apache.catalina.deploy.MessageDestinationRef;
96
import org.apache.catalina.deploy.NamingResources;
97
import org.apache.catalina.deploy.NamingResources;
97
import org.apache.catalina.deploy.SecurityCollection;
98
import org.apache.catalina.deploy.SecurityCollection;
98
import org.apache.catalina.deploy.SecurityConstraint;
99
import org.apache.catalina.deploy.SecurityConstraint;
99
import org.apache.catalina.loader.WebappLoader;
100
import org.apache.catalina.loader.WebappLoader;
100
import org.apache.catalina.session.StandardManager;
101
import org.apache.catalina.session.StandardManager;
101
import org.apache.catalina.startup.TldConfig;
102
import org.apache.catalina.startup.TldConfig;
102
import org.apache.catalina.util.CharsetMapper;
103
import org.apache.catalina.util.CharsetMapper;
103
import org.apache.catalina.util.ContextName;
104
import org.apache.catalina.util.ContextName;
104
import org.apache.catalina.util.ExtensionValidator;
105
import org.apache.catalina.util.ExtensionValidator;
105
import org.apache.catalina.util.RequestUtil;
106
import org.apache.catalina.util.RequestUtil;
106
import org.apache.catalina.util.URLEncoder;
107
import org.apache.catalina.util.URLEncoder;
107
import org.apache.juli.logging.Log;
108
import org.apache.juli.logging.Log;
108
import org.apache.juli.logging.LogFactory;
109
import org.apache.juli.logging.LogFactory;
109
import org.apache.naming.ContextBindings;
110
import org.apache.naming.ContextBindings;
110
import org.apache.naming.resources.BaseDirContext;
111
import org.apache.naming.resources.BaseDirContext;
111
import org.apache.naming.resources.DirContextURLStreamHandler;
112
import org.apache.naming.resources.DirContextURLStreamHandler;
112
import org.apache.naming.resources.FileDirContext;
113
import org.apache.naming.resources.FileDirContext;
113
import org.apache.naming.resources.ProxyDirContext;
114
import org.apache.naming.resources.ProxyDirContext;
114
import org.apache.naming.resources.WARDirContext;
115
import org.apache.naming.resources.WARDirContext;
115
import org.apache.tomcat.InstanceManager;
116
import org.apache.tomcat.InstanceManager;
116
import org.apache.tomcat.JarScanner;
117
import org.apache.tomcat.JarScanner;
117
import org.apache.tomcat.util.ExceptionUtils;
118
import org.apache.tomcat.util.ExceptionUtils;
118
import org.apache.tomcat.util.modeler.Registry;
119
import org.apache.tomcat.util.modeler.Registry;
119
import org.apache.tomcat.util.scan.StandardJarScanner;
120
import org.apache.tomcat.util.scan.StandardJarScanner;
120
121
import org.apache.tomcat.util.threads.DedicatedThreadExecutor;
121
/**
122
122
 * Standard implementation of the <b>Context</b> interface.  Each
123
/**
123
 * child container must be a Wrapper implementation to process the
124
 * Standard implementation of the <b>Context</b> interface.  Each
124
 * requests directed to a particular servlet.
125
 * child container must be a Wrapper implementation to process the
125
 *
126
 * requests directed to a particular servlet.
126
 * @author Craig R. McClanahan
127
 *
127
 * @author Remy Maucherat
128
 * @author Craig R. McClanahan
128
 * @version $Id$
129
 * @author Remy Maucherat
129
 */
130
 * @version $Id$
130
131
 */
131
public class StandardContext extends ContainerBase
132
132
        implements Context, NotificationEmitter {
133
public class StandardContext extends ContainerBase
133
134
        implements Context, NotificationEmitter {
134
    private static final Log log = LogFactory.getLog(StandardContext.class);
135
135
136
    private static final Log log = LogFactory.getLog(StandardContext.class);
136
137
137
    // ----------------------------------------------------------- Constructors
138
138
139
    // ----------------------------------------------------------- Constructors
139
140
140
    /**
141
141
     * Create a new StandardContext component with the default basic Valve.
142
    /**
142
     */
143
     * Create a new StandardContext component with the default basic Valve.
143
    public StandardContext() {
144
     */
144
145
    public StandardContext() {
145
        super();
146
146
        pipeline.setBasic(new StandardContextValve());
147
        super();
147
        broadcaster = new NotificationBroadcasterSupport();
148
        pipeline.setBasic(new StandardContextValve());
148
        // Set defaults
149
        broadcaster = new NotificationBroadcasterSupport();
149
        if (!Globals.STRICT_SERVLET_COMPLIANCE) {
150
        // Set defaults
150
            // Strict servlet compliance requires all extension mapped servlets
151
        if (!Globals.STRICT_SERVLET_COMPLIANCE) {
151
            // to be checked against welcome files
152
            // Strict servlet compliance requires all extension mapped servlets
152
            resourceOnlyServlets.add("jsp");
153
            // to be checked against welcome files
153
        }
154
            resourceOnlyServlets.add("jsp");
154
    }
155
        }
155
156
    }
156
157
157
    // ----------------------------------------------------- Class Variables
158
158
159
    // ----------------------------------------------------- Class Variables
159
160
160
    /**
161
161
     * The descriptive information string for this implementation.
162
    /**
162
     */
163
     * The descriptive information string for this implementation.
163
    private static final String info =
164
     */
164
        "org.apache.catalina.core.StandardContext/1.0";
165
    private static final String info =
165
166
        "org.apache.catalina.core.StandardContext/1.0";
166
167
167
    /**
168
168
     * Array containing the safe characters set.
169
    /**
169
     */
170
     * Array containing the safe characters set.
170
    protected static URLEncoder urlEncoder;
171
     */
171
172
    protected static URLEncoder urlEncoder;
172
173
173
    /**
174
174
     * GMT timezone - all HTTP dates are on GMT
175
    /**
175
     */
176
     * GMT timezone - all HTTP dates are on GMT
176
    static {
177
     */
177
        urlEncoder = new URLEncoder();
178
    static {
178
        urlEncoder.addSafeCharacter('~');
179
        urlEncoder = new URLEncoder();
179
        urlEncoder.addSafeCharacter('-');
180
        urlEncoder.addSafeCharacter('~');
180
        urlEncoder.addSafeCharacter('_');
181
        urlEncoder.addSafeCharacter('-');
181
        urlEncoder.addSafeCharacter('.');
182
        urlEncoder.addSafeCharacter('_');
182
        urlEncoder.addSafeCharacter('*');
183
        urlEncoder.addSafeCharacter('.');
183
        urlEncoder.addSafeCharacter('/');
184
        urlEncoder.addSafeCharacter('*');
184
    }
185
        urlEncoder.addSafeCharacter('/');
185
186
    }
186
187
187
    // ----------------------------------------------------- Instance Variables
188
188
189
    // ----------------------------------------------------- Instance Variables
189
190
190
    /**
191
191
     * Allow multipart/form-data requests to be parsed even when the
192
    /**
192
     * target servlet doesn't specify @MultipartConfig or have a
193
     * Allow multipart/form-data requests to be parsed even when the
193
     * &lt;multipart-config&gt; element.
194
     * target servlet doesn't specify @MultipartConfig or have a
194
     */
195
     * &lt;multipart-config&gt; element.
195
    protected boolean allowCasualMultipartParsing = false;
196
     */
196
     
197
    protected boolean allowCasualMultipartParsing = false;
197
    /**
198
     
198
     * Control whether remaining request data will be read
199
    /**
199
     * (swallowed) even if the request violates a data size constraint.
200
     * Control whether remaining request data will be read
200
     */
201
     * (swallowed) even if the request violates a data size constraint.
201
    private boolean swallowAbortedUploads = true;
202
     */
202
203
    private boolean swallowAbortedUploads = true;
203
    /**
204
204
     * The alternate deployment descriptor name.
205
    /**
205
     */
206
     * The alternate deployment descriptor name.
206
    private String altDDName = null;
207
     */
207
208
    private String altDDName = null;
208
209
209
    /**
210
210
     * Lifecycle provider.
211
    /**
211
     */
212
     * Lifecycle provider.
212
    private InstanceManager instanceManager = null;
213
     */
213
214
    private InstanceManager instanceManager = null;
214
215
215
   /**
216
216
     * Associated host name.
217
   /**
217
     */
218
     * Associated host name.
218
    private String hostName;
219
     */
219
220
    private String hostName;
220
221
221
    /**
222
222
     * The antiJARLocking flag for this Context.
223
    /**
223
     */
224
     * The antiJARLocking flag for this Context.
224
    private boolean antiJARLocking = false;
225
     */
225
226
    private boolean antiJARLocking = false;
226
    
227
227
    /**
228
    
228
     * The antiResourceLocking flag for this Context.
229
    /**
229
     */
230
     * The antiResourceLocking flag for this Context.
230
    private boolean antiResourceLocking = false;
231
     */
231
232
    private boolean antiResourceLocking = false;
232
    
233
233
    /**
234
    
234
     * The set of application listener class names configured for this
235
    /**
235
     * application, in the order they were encountered in the web.xml file.
236
     * The set of application listener class names configured for this
236
     */
237
     * application, in the order they were encountered in the web.xml file.
237
    private String applicationListeners[] = new String[0];
238
     */
238
    
239
    private String applicationListeners[] = new String[0];
239
    private final Object applicationListenersLock = new Object();
240
    
240
241
    private final Object applicationListenersLock = new Object();
241
242
242
    /**
243
243
     * The set of instantiated application event listener objects</code>.
244
    /**
244
     */
245
     * The set of instantiated application event listener objects</code>.
245
    private Object applicationEventListenersObjects[] = 
246
     */
246
        new Object[0];
247
    private Object applicationEventListenersObjects[] = 
247
248
        new Object[0];
248
249
249
    /**
250
250
     * The set of instantiated application lifecycle listener objects</code>.
251
    /**
251
     */
252
     * The set of instantiated application lifecycle listener objects</code>.
252
    private Object applicationLifecycleListenersObjects[] = 
253
     */
253
        new Object[0];
254
    private Object applicationLifecycleListenersObjects[] = 
254
255
        new Object[0];
255
256
256
    /**
257
257
     * The ordered set of ServletContainerInitializers for this web application.
258
    /**
258
     */
259
     * The ordered set of ServletContainerInitializers for this web application.
259
    private Map<ServletContainerInitializer,Set<Class<?>>> initializers =
260
     */
260
        new LinkedHashMap<ServletContainerInitializer,Set<Class<?>>>();
261
    private Map<ServletContainerInitializer,Set<Class<?>>> initializers =
261
    
262
        new LinkedHashMap<ServletContainerInitializer,Set<Class<?>>>();
262
    
263
    
263
    /**
264
    
264
     * The set of application parameters defined for this application.
265
    /**
265
     */
266
     * The set of application parameters defined for this application.
266
    private ApplicationParameter applicationParameters[] =
267
     */
267
        new ApplicationParameter[0];
268
    private ApplicationParameter applicationParameters[] =
268
269
        new ApplicationParameter[0];
269
    private final Object applicationParametersLock = new Object();
270
270
    
271
    private final Object applicationParametersLock = new Object();
271
272
    
272
    /**
273
273
     * The broadcaster that sends j2ee notifications. 
274
    /**
274
     */
275
     * The broadcaster that sends j2ee notifications. 
275
    private NotificationBroadcasterSupport broadcaster = null;
276
     */
276
    
277
    private NotificationBroadcasterSupport broadcaster = null;
277
    /**
278
    
278
     * The Locale to character set mapper for this application.
279
    /**
279
     */
280
     * The Locale to character set mapper for this application.
280
    private CharsetMapper charsetMapper = null;
281
     */
281
282
    private CharsetMapper charsetMapper = null;
282
283
283
    /**
284
284
     * The Java class name of the CharsetMapper class to be created.
285
    /**
285
     */
286
     * The Java class name of the CharsetMapper class to be created.
286
    private String charsetMapperClass =
287
     */
287
      "org.apache.catalina.util.CharsetMapper";
288
    private String charsetMapperClass =
288
289
      "org.apache.catalina.util.CharsetMapper";
289
290
290
    /**
291
291
     * The URL of the XML descriptor for this context.
292
    /**
292
     */
293
     * The URL of the XML descriptor for this context.
293
    private URL configFile = null;
294
     */
294
295
    private URL configFile = null;
295
296
296
    /**
297
297
     * The "correctly configured" flag for this Context.
298
    /**
298
     */
299
     * The "correctly configured" flag for this Context.
299
    private boolean configured = false;
300
     */
300
301
    private boolean configured = false;
301
302
302
    /**
303
303
     * The security constraints for this web application.
304
    /**
304
     */
305
     * The security constraints for this web application.
305
    private volatile SecurityConstraint constraints[] =
306
     */
306
            new SecurityConstraint[0];
307
    private volatile SecurityConstraint constraints[] =
307
    
308
            new SecurityConstraint[0];
308
    private final Object constraintsLock = new Object();
309
    
309
310
    private final Object constraintsLock = new Object();
310
311
311
    /**
312
312
     * The ServletContext implementation associated with this Context.
313
    /**
313
     */
314
     * The ServletContext implementation associated with this Context.
314
    protected ApplicationContext context = null;
315
     */
315
316
    protected ApplicationContext context = null;
316
317
317
    /**
318
318
     * Compiler classpath to use.
319
    /**
319
     */
320
     * Compiler classpath to use.
320
    private String compilerClasspath = null;
321
     */
321
322
    private String compilerClasspath = null;
322
323
323
    /**
324
324
     * Should we attempt to use cookies for session id communication?
325
    /**
325
     */
326
     * Should we attempt to use cookies for session id communication?
326
    private boolean cookies = true;
327
     */
327
328
    private boolean cookies = true;
328
329
329
    /**
330
330
     * Should we allow the <code>ServletContext.getContext()</code> method
331
    /**
331
     * to access the context of other web applications in this server?
332
     * Should we allow the <code>ServletContext.getContext()</code> method
332
     */
333
     * to access the context of other web applications in this server?
333
    private boolean crossContext = false;
334
     */
334
335
    private boolean crossContext = false;
335
    
336
336
    /**
337
    
337
     * Encoded path.
338
    /**
338
     */
339
     * Encoded path.
339
    private String encodedPath = null;
340
     */
340
    
341
    private String encodedPath = null;
341
342
    
342
    /**
343
343
     * Unencoded path for this web application.
344
    /**
344
     */
345
     * Unencoded path for this web application.
345
    private String path = null;
346
     */
346
347
    private String path = null;
347
348
348
    /**
349
349
     * The "follow standard delegation model" flag that will be used to
350
    /**
350
     * configure our ClassLoader.
351
     * The "follow standard delegation model" flag that will be used to
351
     */
352
     * configure our ClassLoader.
352
    private boolean delegate = false;
353
     */
353
354
    private boolean delegate = false;
354
355
355
    /**
356
356
     * The display name of this web application.
357
    /**
357
     */
358
     * The display name of this web application.
358
    private String displayName = null;
359
     */
359
360
    private String displayName = null;
360
361
361
    /** 
362
362
     * Override the default context xml location.
363
    /** 
363
     */
364
     * Override the default context xml location.
364
    private String defaultContextXml;
365
     */
365
366
    private String defaultContextXml;
366
367
367
    /** 
368
368
     * Override the default web xml location.
369
    /** 
369
     */
370
     * Override the default web xml location.
370
    private String defaultWebXml;
371
     */
371
372
    private String defaultWebXml;
372
373
373
    /**
374
374
     * The distributable flag for this web application.
375
    /**
375
     */
376
     * The distributable flag for this web application.
376
    private boolean distributable = false;
377
     */
377
378
    private boolean distributable = false;
378
379
379
    /**
380
380
     * The document root for this web application.
381
    /**
381
     */
382
     * The document root for this web application.
382
    private String docBase = null;
383
     */
383
384
    private String docBase = null;
384
385
385
    /**
386
386
     * The exception pages for this web application, keyed by fully qualified
387
    /**
387
     * class name of the Java exception.
388
     * The exception pages for this web application, keyed by fully qualified
388
     */
389
     * class name of the Java exception.
389
    private HashMap<String, ErrorPage> exceptionPages =
390
     */
390
        new HashMap<String, ErrorPage>();
391
    private HashMap<String, ErrorPage> exceptionPages =
391
392
        new HashMap<String, ErrorPage>();
392
393
393
    /**
394
394
     * The set of filter configurations (and associated filter instances) we
395
    /**
395
     * have initialized, keyed by filter name.
396
     * The set of filter configurations (and associated filter instances) we
396
     */
397
     * have initialized, keyed by filter name.
397
    private HashMap<String, ApplicationFilterConfig> filterConfigs =
398
     */
398
        new HashMap<String, ApplicationFilterConfig>();
399
    private HashMap<String, ApplicationFilterConfig> filterConfigs =
399
400
        new HashMap<String, ApplicationFilterConfig>();
400
401
401
    /**
402
402
     * The set of filter definitions for this application, keyed by
403
    /**
403
     * filter name.
404
     * The set of filter definitions for this application, keyed by
404
     */
405
     * filter name.
405
    private HashMap<String, FilterDef> filterDefs =
406
     */
406
        new HashMap<String, FilterDef>();
407
    private HashMap<String, FilterDef> filterDefs =
407
408
        new HashMap<String, FilterDef>();
408
409
409
    /**
410
410
     * The set of filter mappings for this application, in the order
411
    /**
411
     * they were defined in the deployment descriptor with additional mappings
412
     * The set of filter mappings for this application, in the order
412
     * added via the {@link ServletContext} possibly both before and after those
413
     * they were defined in the deployment descriptor with additional mappings
413
     * defined in the deployment descriptor.
414
     * added via the {@link ServletContext} possibly both before and after those
414
     */
415
     * defined in the deployment descriptor.
415
    private final ContextFilterMaps filterMaps = new ContextFilterMaps();
416
     */
416
417
    private final ContextFilterMaps filterMaps = new ContextFilterMaps();
417
    /**
418
418
     * Ignore annotations.
419
    /**
419
     */
420
     * Ignore annotations.
420
    private boolean ignoreAnnotations = false;
421
     */
421
422
    private boolean ignoreAnnotations = false;
422
423
423
    /**
424
424
     * The set of classnames of InstanceListeners that will be added
425
    /**
425
     * to each newly created Wrapper by <code>createWrapper()</code>.
426
     * The set of classnames of InstanceListeners that will be added
426
     */
427
     * to each newly created Wrapper by <code>createWrapper()</code>.
427
    private String instanceListeners[] = new String[0];
428
     */
428
429
    private String instanceListeners[] = new String[0];
429
    private final Object instanceListenersLock = new Object();
430
430
431
    private final Object instanceListenersLock = new Object();
431
432
432
    /**
433
433
     * The login configuration descriptor for this web application.
434
    /**
434
     */
435
     * The login configuration descriptor for this web application.
435
    private LoginConfig loginConfig = null;
436
     */
436
437
    private LoginConfig loginConfig = null;
437
438
438
    /**
439
439
     * The mapper associated with this context.
440
    /**
440
     */
441
     * The mapper associated with this context.
441
    private org.apache.tomcat.util.http.mapper.Mapper mapper = 
442
     */
442
        new org.apache.tomcat.util.http.mapper.Mapper();
443
    private org.apache.tomcat.util.http.mapper.Mapper mapper = 
443
444
        new org.apache.tomcat.util.http.mapper.Mapper();
444
445
445
    /**
446
446
     * The naming context listener for this web application.
447
    /**
447
     */
448
     * The naming context listener for this web application.
448
    private NamingContextListener namingContextListener = null;
449
     */
449
450
    private NamingContextListener namingContextListener = null;
450
451
451
    /**
452
452
     * The naming resources for this web application.
453
    /**
453
     */
454
     * The naming resources for this web application.
454
    private NamingResources namingResources = null;
455
     */
455
456
    private NamingResources namingResources = null;
456
    /**
457
457
     * The message destinations for this web application.
458
    /**
458
     */
459
     * The message destinations for this web application.
459
    private HashMap<String, MessageDestination> messageDestinations =
460
     */
460
        new HashMap<String, MessageDestination>();
461
    private HashMap<String, MessageDestination> messageDestinations =
461
462
        new HashMap<String, MessageDestination>();
462
463
463
    /**
464
464
     * The MIME mappings for this web application, keyed by extension.
465
    /**
465
     */
466
     * The MIME mappings for this web application, keyed by extension.
466
    private HashMap<String, String> mimeMappings =
467
     */
467
        new HashMap<String, String>();
468
    private HashMap<String, String> mimeMappings =
468
469
        new HashMap<String, String>();
469
470
470
     /**
471
471
      * Special case: error page for status 200.
472
     /**
472
      */
473
      * Special case: error page for status 200.
473
     private ErrorPage okErrorPage = null;
474
      */
474
475
     private ErrorPage okErrorPage = null;
475
476
476
    /**
477
477
     * The context initialization parameters for this web application,
478
    /**
478
     * keyed by name.
479
     * The context initialization parameters for this web application,
479
     */
480
     * keyed by name.
480
    private HashMap<String, String> parameters = new HashMap<String, String>();
481
     */
481
482
    private HashMap<String, String> parameters = new HashMap<String, String>();
482
483
483
    /**
484
484
     * The request processing pause flag (while reloading occurs)
485
    /**
485
     */
486
     * The request processing pause flag (while reloading occurs)
486
    private boolean paused = false;
487
     */
487
488
    private boolean paused = false;
488
489
489
    /**
490
490
     * The public identifier of the DTD for the web application deployment
491
    /**
491
     * descriptor version we are currently parsing.  This is used to support
492
     * The public identifier of the DTD for the web application deployment
492
     * relaxed validation rules when processing version 2.2 web.xml files.
493
     * descriptor version we are currently parsing.  This is used to support
493
     */
494
     * relaxed validation rules when processing version 2.2 web.xml files.
494
    private String publicId = null;
495
     */
495
496
    private String publicId = null;
496
497
497
    /**
498
498
     * The reloadable flag for this web application.
499
    /**
499
     */
500
     * The reloadable flag for this web application.
500
    private boolean reloadable = false;
501
     */
501
502
    private boolean reloadable = false;
502
503
503
    /**
504
504
     * Unpack WAR property.
505
    /**
505
     */
506
     * Unpack WAR property.
506
    private boolean unpackWAR = true;
507
     */
507
508
    private boolean unpackWAR = true;
508
509
509
    /**
510
510
     * The default context override flag for this web application.
511
    /**
511
     */
512
     * The default context override flag for this web application.
512
    private boolean override = false;
513
     */
513
514
    private boolean override = false;
514
515
515
    /**
516
516
     * The original document root for this web application.
517
    /**
517
     */
518
     * The original document root for this web application.
518
    private String originalDocBase = null;
519
     */
519
    
520
    private String originalDocBase = null;
520
    
521
    
521
    /**
522
    
522
     * The privileged flag for this web application.
523
    /**
523
     */
524
     * The privileged flag for this web application.
524
    private boolean privileged = false;
525
     */
525
526
    private boolean privileged = false;
526
527
527
    /**
528
528
     * Should the next call to <code>addWelcomeFile()</code> cause replacement
529
    /**
529
     * of any existing welcome files?  This will be set before processing the
530
     * Should the next call to <code>addWelcomeFile()</code> cause replacement
530
     * web application's deployment descriptor, so that application specified
531
     * of any existing welcome files?  This will be set before processing the
531
     * choices <strong>replace</strong>, rather than append to, those defined
532
     * web application's deployment descriptor, so that application specified
532
     * in the global descriptor.
533
     * choices <strong>replace</strong>, rather than append to, those defined
533
     */
534
     * in the global descriptor.
534
    private boolean replaceWelcomeFiles = false;
535
     */
535
536
    private boolean replaceWelcomeFiles = false;
536
537
537
    /**
538
538
     * The security role mappings for this application, keyed by role
539
    /**
539
     * name (as used within the application).
540
     * The security role mappings for this application, keyed by role
540
     */
541
     * name (as used within the application).
541
    private HashMap<String, String> roleMappings =
542
     */
542
        new HashMap<String, String>();
543
    private HashMap<String, String> roleMappings =
543
544
        new HashMap<String, String>();
544
545
545
    /**
546
546
     * The security roles for this application, keyed by role name.
547
    /**
547
     */
548
     * The security roles for this application, keyed by role name.
548
    private String securityRoles[] = new String[0];
549
     */
549
550
    private String securityRoles[] = new String[0];
550
    private final Object securityRolesLock = new Object();
551
551
552
    private final Object securityRolesLock = new Object();
552
553
553
    /**
554
554
     * The servlet mappings for this web application, keyed by
555
    /**
555
     * matching pattern.
556
     * The servlet mappings for this web application, keyed by
556
     */
557
     * matching pattern.
557
    private HashMap<String, String> servletMappings =
558
     */
558
        new HashMap<String, String>();
559
    private HashMap<String, String> servletMappings =
559
    
560
        new HashMap<String, String>();
560
    private final Object servletMappingsLock = new Object();
561
    
561
562
    private final Object servletMappingsLock = new Object();
562
563
563
    /**
564
564
     * The session timeout (in minutes) for this web application.
565
    /**
565
     */
566
     * The session timeout (in minutes) for this web application.
566
    private int sessionTimeout = 30;
567
     */
567
568
    private int sessionTimeout = 30;
568
    /**
569
569
     * The notification sequence number.
570
    /**
570
     */
571
     * The notification sequence number.
571
    private AtomicLong sequenceNumber = new AtomicLong(0);
572
     */
572
    
573
    private AtomicLong sequenceNumber = new AtomicLong(0);
573
    /**
574
    
574
     * The status code error pages for this web application, keyed by
575
    /**
575
     * HTTP status code (as an Integer).
576
     * The status code error pages for this web application, keyed by
576
     */
577
     * HTTP status code (as an Integer).
577
    private HashMap<Integer, ErrorPage> statusPages =
578
     */
578
        new HashMap<Integer, ErrorPage>();
579
    private HashMap<Integer, ErrorPage> statusPages =
579
580
        new HashMap<Integer, ErrorPage>();
580
581
581
    /**
582
582
     * Set flag to true to cause the system.out and system.err to be redirected
583
    /**
583
     * to the logger when executing a servlet.
584
     * Set flag to true to cause the system.out and system.err to be redirected
584
     */
585
     * to the logger when executing a servlet.
585
    private boolean swallowOutput = false;
586
     */
586
587
    private boolean swallowOutput = false;
587
588
588
    /**
589
589
     * Amount of ms that the container will wait for servlets to unload.
590
    /**
590
     */
591
     * Amount of ms that the container will wait for servlets to unload.
591
    private long unloadDelay = 2000;
592
     */
592
593
    private long unloadDelay = 2000;
593
594
594
    /**
595
595
     * The watched resources for this application.
596
    /**
596
     */
597
     * The watched resources for this application.
597
    private String watchedResources[] = new String[0];
598
     */
598
599
    private String watchedResources[] = new String[0];
599
    private final Object watchedResourcesLock = new Object();
600
600
601
    private final Object watchedResourcesLock = new Object();
601
602
602
    /**
603
603
     * The welcome files for this application.
604
    /**
604
     */
605
     * The welcome files for this application.
605
    private String welcomeFiles[] = new String[0];
606
     */
606
607
    private String welcomeFiles[] = new String[0];
607
    private final Object welcomeFilesLock = new Object();
608
608
609
    private final Object welcomeFilesLock = new Object();
609
610
610
    /**
611
611
     * The set of classnames of LifecycleListeners that will be added
612
    /**
612
     * to each newly created Wrapper by <code>createWrapper()</code>.
613
     * The set of classnames of LifecycleListeners that will be added
613
     */
614
     * to each newly created Wrapper by <code>createWrapper()</code>.
614
    private String wrapperLifecycles[] = new String[0];
615
     */
615
616
    private String wrapperLifecycles[] = new String[0];
616
    private final Object wrapperLifecyclesLock = new Object();
617
617
618
    private final Object wrapperLifecyclesLock = new Object();
618
    /**
619
619
     * The set of classnames of ContainerListeners that will be added
620
    /**
620
     * to each newly created Wrapper by <code>createWrapper()</code>.
621
     * The set of classnames of ContainerListeners that will be added
621
     */
622
     * to each newly created Wrapper by <code>createWrapper()</code>.
622
    private String wrapperListeners[] = new String[0];
623
     */
623
624
    private String wrapperListeners[] = new String[0];
624
    private final Object wrapperListenersLock = new Object();
625
625
626
    private final Object wrapperListenersLock = new Object();
626
    /**
627
627
     * The pathname to the work directory for this context (relative to
628
    /**
628
     * the server's home if not absolute).
629
     * The pathname to the work directory for this context (relative to
629
     */
630
     * the server's home if not absolute).
630
    private String workDir = null;
631
     */
631
632
    private String workDir = null;
632
633
633
    /**
634
634
     * Java class name of the Wrapper class implementation we use.
635
    /**
635
     */
636
     * Java class name of the Wrapper class implementation we use.
636
    private String wrapperClassName = StandardWrapper.class.getName();
637
     */
637
    private Class<?> wrapperClass = null;
638
    private String wrapperClassName = StandardWrapper.class.getName();
638
639
    private Class<?> wrapperClass = null;
639
640
640
    /**
641
641
     * JNDI use flag.
642
    /**
642
     */
643
     * JNDI use flag.
643
    private boolean useNaming = true;
644
     */
644
645
    private boolean useNaming = true;
645
646
646
    /**
647
647
     * Filesystem based flag.
648
    /**
648
     */
649
     * Filesystem based flag.
649
    private boolean filesystemBased = false;
650
     */
650
651
    private boolean filesystemBased = false;
651
652
652
    /**
653
653
     * Name of the associated naming context.
654
    /**
654
     */
655
     * Name of the associated naming context.
655
    private String namingContextName = null;
656
     */
656
657
    private String namingContextName = null;
657
658
658
    /**
659
659
     * Caching allowed flag.
660
    /**
660
     */
661
     * Caching allowed flag.
661
    private boolean cachingAllowed = true;
662
     */
662
663
    private boolean cachingAllowed = true;
663
664
664
    /**
665
665
     * Allow linking.
666
    /**
666
     */
667
     * Allow linking.
667
    protected boolean allowLinking = false;
668
     */
668
669
    protected boolean allowLinking = false;
669
670
670
    /**
671
671
     * Cache max size in KB.
672
    /**
672
     */
673
     * Cache max size in KB.
673
    protected int cacheMaxSize = 10240; // 10 MB
674
     */
674
675
    protected int cacheMaxSize = 10240; // 10 MB
675
676
676
    /**
677
677
     * Cache object max size in KB.
678
    /**
678
     */
679
     * Cache object max size in KB.
679
    protected int cacheObjectMaxSize = 512; // 512K
680
     */
680
681
    protected int cacheObjectMaxSize = 512; // 512K
681
682
682
    /**
683
683
     * Cache TTL in ms.
684
    /**
684
     */
685
     * Cache TTL in ms.
685
    protected int cacheTTL = 5000;
686
     */
686
687
    protected int cacheTTL = 5000;
687
688
688
    /**
689
689
     * List of resource aliases.
690
    /**
690
     */
691
     * List of resource aliases.
691
    private String aliases = null;
692
     */
692
693
    private String aliases = null;
693
694
694
    /**
695
695
     * Non proxied resources.
696
    /**
696
     */
697
     * Non proxied resources.
697
    private DirContext webappResources = null;
698
     */
698
699
    private DirContext webappResources = null;
699
    private long startupTime;
700
700
    private long startTime;
701
    private long startupTime;
701
    private long tldScanTime;
702
    private long startTime;
702
703
    private long tldScanTime;
703
    /** 
704
704
     * Name of the engine. If null, the domain is used.
705
    /** 
705
     */ 
706
     * Name of the engine. If null, the domain is used.
706
    private String j2EEApplication="none";
707
     */ 
707
    private String j2EEServer="none";
708
    private String j2EEApplication="none";
708
709
    private String j2EEServer="none";
709
710
710
    /**
711
711
     * Attribute value used to turn on/off XML validation
712
    /**
712
     */
713
     * Attribute value used to turn on/off XML validation
713
    private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE;
714
     */
714
715
    private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE;
715
716
716
    /**
717
717
     * Attribute value used to turn on/off XML namespace validation
718
    /**
718
     */
719
     * Attribute value used to turn on/off XML namespace validation
719
    private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
720
     */
720
721
    private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
721
    /**
722
722
     * Attribute value used to turn on/off TLD processing
723
    /**
723
     */
724
     * Attribute value used to turn on/off TLD processing
724
    private boolean processTlds = true;
725
     */
725
726
    private boolean processTlds = true;
726
    /**
727
727
     * Attribute value used to turn on/off XML validation
728
    /**
728
     */
729
     * Attribute value used to turn on/off XML validation
729
    private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE;
730
     */
730
731
    private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE;
731
732
732
    /**
733
733
     * Attribute value used to turn on/off TLD XML namespace validation
734
    /**
734
     */
735
     * Attribute value used to turn on/off TLD XML namespace validation
735
    private boolean tldNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
736
     */
736
737
    private boolean tldNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
737
738
738
    /**
739
739
     * Should we save the configuration.
740
    /**
740
     */
741
     * Should we save the configuration.
741
    private boolean saveConfig = true;
742
     */
742
743
    private boolean saveConfig = true;
743
    
744
744
    /**
745
    
745
     * The name to use for session cookies. <code>null</code> indicates that
746
    /**
746
     * the name is controlled by the application.
747
     * The name to use for session cookies. <code>null</code> indicates that
747
     */
748
     * the name is controlled by the application.
748
    private String sessionCookieName;
749
     */
749
    
750
    private String sessionCookieName;
750
    
751
    
751
    /**
752
    
752
     * The flag that indicates that session cookies should use HttpOnly
753
    /**
753
     */
754
     * The flag that indicates that session cookies should use HttpOnly
754
    private boolean useHttpOnly = true;
755
     */
755
756
    private boolean useHttpOnly = true;
756
    
757
757
    /**
758
    
758
     * The domain to use for session cookies. <code>null</code> indicates that
759
    /**
759
     * the domain is controlled by the application.
760
     * The domain to use for session cookies. <code>null</code> indicates that
760
     */
761
     * the domain is controlled by the application.
761
    private String sessionCookieDomain;
762
     */
762
    
763
    private String sessionCookieDomain;
763
    
764
    
764
    /**
765
    
765
     * The path to use for session cookies. <code>null</code> indicates that
766
    /**
766
     * the path is controlled by the application.
767
     * The path to use for session cookies. <code>null</code> indicates that
767
     */
768
     * the path is controlled by the application.
768
    private String sessionCookiePath;
769
     */
769
    
770
    private String sessionCookiePath;
770
    
771
    
771
    /**
772
    
772
     * Is a / added to the end of the session cookie path to ensure browsers,
773
    /**
773
     * particularly IE, don't send a session cookie for context /foo with
774
     * Is a / added to the end of the session cookie path to ensure browsers,
774
     * requests intended for context /foobar.
775
     * particularly IE, don't send a session cookie for context /foo with
775
     */
776
     * requests intended for context /foobar.
776
    private boolean sessionCookiePathUsesTrailingSlash = true;
777
     */
777
778
    private boolean sessionCookiePathUsesTrailingSlash = true;
778
779
779
    /**
780
780
     * The Jar scanner to use to search for Jars that might contain
781
    /**
781
     * configuration information such as TLDs or web-fragment.xml files. 
782
     * The Jar scanner to use to search for Jars that might contain
782
     */
783
     * configuration information such as TLDs or web-fragment.xml files. 
783
    private JarScanner jarScanner = null;
784
     */
784
785
    private JarScanner jarScanner = null;
785
    /**
786
786
     * Should Tomcat attempt to null out any static or final fields from loaded
787
    /**
787
     * classes when a web application is stopped as a work around for apparent
788
     * Should Tomcat attempt to null out any static or final fields from loaded
788
     * garbage collection bugs and application coding errors? There have been
789
     * classes when a web application is stopped as a work around for apparent
789
     * some issues reported with log4j when this option is true. Applications
790
     * garbage collection bugs and application coding errors? There have been
790
     * without memory leaks using recent JVMs should operate correctly with this
791
     * some issues reported with log4j when this option is true. Applications
791
     * option set to <code>false</code>. If not specified, the default value of
792
     * without memory leaks using recent JVMs should operate correctly with this
792
     * <code>false</code> will be used. 
793
     * option set to <code>false</code>. If not specified, the default value of
793
     */
794
     * <code>false</code> will be used. 
794
    private boolean clearReferencesStatic = false;
795
     */
795
    
796
    private boolean clearReferencesStatic = false;
796
    /**
797
    
797
     * Should Tomcat attempt to terminate threads that have been started by the
798
    /**
798
     * web application? Stopping threads is performed via the deprecated (for
799
     * Should Tomcat attempt to terminate threads that have been started by the
799
     * good reason) <code>Thread.stop()</code> method and is likely to result in
800
     * web application? Stopping threads is performed via the deprecated (for
800
     * instability. As such, enabling this should be viewed as an option of last
801
     * good reason) <code>Thread.stop()</code> method and is likely to result in
801
     * resort in a development environment and is not recommended in a
802
     * instability. As such, enabling this should be viewed as an option of last
802
     * production environment. If not specified, the default value of
803
     * resort in a development environment and is not recommended in a
803
     * <code>false</code> will be used.
804
     * production environment. If not specified, the default value of
804
     */
805
     * <code>false</code> will be used.
805
    private boolean clearReferencesStopThreads = false;
806
     */
806
807
    private boolean clearReferencesStopThreads = false;
807
    /**
808
808
     * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
809
    /**
809
     * that have been started by the web application? If not specified, the
810
     * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
810
     * default value of <code>false</code> will be used.
811
     * that have been started by the web application? If not specified, the
811
     */
812
     * default value of <code>false</code> will be used.
812
    private boolean clearReferencesStopTimerThreads = false;
813
     */
813
814
    private boolean clearReferencesStopTimerThreads = false;
814
    /**
815
815
     * If an HttpClient keep-alive timer thread has been started by this web
816
    /**
816
     * application and is still running, should Tomcat change the context class
817
     * If an HttpClient keep-alive timer thread has been started by this web
817
     * loader from the current {@link WebappClassLoader} to
818
     * application and is still running, should Tomcat change the context class
818
     * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
819
     * loader from the current {@link WebappClassLoader} to
819
     * keep-alive timer thread will stop on its own once the keep-alives all
820
     * {@link WebappClassLoader#parent} to prevent a memory leak? Note that the
820
     * expire however, on a busy system that might not happen for some time.
821
     * keep-alive timer thread will stop on its own once the keep-alives all
821
     */
822
     * expire however, on a busy system that might not happen for some time.
822
    private boolean clearReferencesHttpClientKeepAliveThread = true;
823
     */
823
824
    private boolean clearReferencesHttpClientKeepAliveThread = true;
824
    /**
825
825
     * Should Tomcat renew the threads of the thread pool when the application
826
    /**
826
     * is stopped to avoid memory leaks because of uncleaned ThreadLocal
827
     * Should Tomcat renew the threads of the thread pool when the application
827
     * variables. This also requires that the threadRenewalDelay property of the
828
     * is stopped to avoid memory leaks because of uncleaned ThreadLocal
828
     * StandardThreadExecutor of ThreadPoolExecutor be set to a positive value.
829
     * variables. This also requires that the threadRenewalDelay property of the
829
     */
830
     * StandardThreadExecutor of ThreadPoolExecutor be set to a positive value.
830
    private boolean renewThreadsWhenStoppingContext = true;
831
     */
831
    
832
    private boolean renewThreadsWhenStoppingContext = true;
832
    /**
833
    
833
     * Should the effective web.xml be logged when the context starts?
834
    /**
834
     */
835
     * Should the effective web.xml be logged when the context starts?
835
    private boolean logEffectiveWebXml = false;
836
     */
836
837
    private boolean logEffectiveWebXml = false;
837
    private int effectiveMajorVersion = 3;
838
838
    
839
    private int effectiveMajorVersion = 3;
839
    private int effectiveMinorVersion = 0;
840
    
840
841
    private int effectiveMinorVersion = 0;
841
    private JspConfigDescriptor jspConfigDescriptor =
842
842
        new ApplicationJspConfigDescriptor();
843
    private JspConfigDescriptor jspConfigDescriptor =
843
844
        new ApplicationJspConfigDescriptor();
844
    private Set<String> resourceOnlyServlets = new HashSet<String>();
845
845
846
    private Set<String> resourceOnlyServlets = new HashSet<String>();
846
    private String webappVersion = "";
847
847
848
    private String webappVersion = "";
848
    private boolean addWebinfClassesResources = false;
849
849
    
850
    private boolean addWebinfClassesResources = false;
850
    private boolean fireRequestListenersOnForwards = false;
851
    
851
852
    private boolean fireRequestListenersOnForwards = false;
852
    /**
853
853
     * Servlets created via {@link ApplicationContext#createServlet(Class)} for
854
    /**
854
     * tracking purposes.
855
     * Servlets created via {@link ApplicationContext#createServlet(Class)} for
855
     */
856
     * tracking purposes.
856
    private Set<Servlet> createdServlets = new HashSet<Servlet>();
857
     */
857
858
    private Set<Servlet> createdServlets = new HashSet<Servlet>();
858
    private boolean preemptiveAuthentication = false;
859
859
860
    private boolean preemptiveAuthentication = false;
860
    private boolean sendRedirectBody = false;
861
861
862
    private boolean sendRedirectBody = false;
862
    
863
863
    // ----------------------------------------------------- Context Properties
864
    
864
    
865
    // ----------------------------------------------------- Context Properties
865
    @Override
866
    
866
    public boolean getSendRedirectBody() {
867
    @Override
867
        return sendRedirectBody;
868
    public boolean getSendRedirectBody() {
868
    }
869
        return sendRedirectBody;
869
870
    }
870
871
871
    @Override
872
872
    public void setSendRedirectBody(boolean sendRedirectBody) {
873
    @Override
873
        this.sendRedirectBody = sendRedirectBody;
874
    public void setSendRedirectBody(boolean sendRedirectBody) {
874
    }
875
        this.sendRedirectBody = sendRedirectBody;
875
876
    }
876
877
877
    @Override
878
878
    public boolean getPreemptiveAuthentication() {
879
    @Override
879
        return preemptiveAuthentication;
880
    public boolean getPreemptiveAuthentication() {
880
    }
881
        return preemptiveAuthentication;
881
882
    }
882
883
883
    @Override
884
884
    public void setPreemptiveAuthentication(boolean preemptiveAuthentication) {
885
    @Override
885
        this.preemptiveAuthentication = preemptiveAuthentication;
886
    public void setPreemptiveAuthentication(boolean preemptiveAuthentication) {
886
    }
887
        this.preemptiveAuthentication = preemptiveAuthentication;
887
888
    }
888
889
889
    @Override
890
890
    public void setFireRequestListenersOnForwards(boolean enable) {
891
    @Override
891
        fireRequestListenersOnForwards = enable;
892
    public void setFireRequestListenersOnForwards(boolean enable) {
892
    }
893
        fireRequestListenersOnForwards = enable;
893
894
    }
894
895
895
    @Override
896
896
    public boolean getFireRequestListenersOnForwards() {
897
    @Override
897
        return fireRequestListenersOnForwards;
898
    public boolean getFireRequestListenersOnForwards() {
898
    }
899
        return fireRequestListenersOnForwards;
899
900
    }
900
901
901
    public void setAddWebinfClassesResources(
902
902
            boolean addWebinfClassesResources) {
903
    public void setAddWebinfClassesResources(
903
        this.addWebinfClassesResources = addWebinfClassesResources;
904
            boolean addWebinfClassesResources) {
904
    }
905
        this.addWebinfClassesResources = addWebinfClassesResources;
905
906
    }
906
907
907
    public boolean getAddWebinfClassesResources() {
908
908
        return addWebinfClassesResources;
909
    public boolean getAddWebinfClassesResources() {
909
    }
910
        return addWebinfClassesResources;
910
911
    }
911
912
912
    @Override
913
913
    public void setWebappVersion(String webappVersion) {
914
    @Override
914
        if (null == webappVersion) {
915
    public void setWebappVersion(String webappVersion) {
915
            this.webappVersion = "";
916
        if (null == webappVersion) {
916
        } else {
917
            this.webappVersion = "";
917
            this.webappVersion = webappVersion;
918
        } else {
918
        }
919
            this.webappVersion = webappVersion;
919
    }
920
        }
920
921
    }
921
922
922
    @Override
923
923
    public String getWebappVersion() {
924
    @Override
924
        return webappVersion;
925
    public String getWebappVersion() {
925
    }
926
        return webappVersion;
926
927
    }
927
928
928
    @Override
929
929
    public String getBaseName() {
930
    @Override
930
        return new ContextName(path, webappVersion).getBaseName();
931
    public String getBaseName() {
931
    }
932
        return new ContextName(path, webappVersion).getBaseName();
932
933
    }
933
934
934
    @Override
935
935
    public String getResourceOnlyServlets() {
936
    @Override
936
        StringBuilder result = new StringBuilder();
937
    public String getResourceOnlyServlets() {
937
        boolean first = true;
938
        StringBuilder result = new StringBuilder();
938
        for (String servletName : resourceOnlyServlets) {
939
        boolean first = true;
939
            if (!first) {
940
        for (String servletName : resourceOnlyServlets) {
940
                result.append(',');
941
            if (!first) {
941
            }
942
                result.append(',');
942
            result.append(servletName);
943
            }
943
        }
944
            result.append(servletName);
944
        return result.toString();
945
        }
945
    }
946
        return result.toString();
946
947
    }
947
948
948
    @Override
949
949
    public void setResourceOnlyServlets(String resourceOnlyServlets) {
950
    @Override
950
        this.resourceOnlyServlets.clear();
951
    public void setResourceOnlyServlets(String resourceOnlyServlets) {
951
        if (resourceOnlyServlets == null) {
952
        this.resourceOnlyServlets.clear();
952
            return;
953
        if (resourceOnlyServlets == null) {
953
        }
954
            return;
954
        for (String servletName : resourceOnlyServlets.split(",")) {
955
        }
955
            servletName = servletName.trim();
956
        for (String servletName : resourceOnlyServlets.split(",")) {
956
            if (servletName.length()>0) {
957
            servletName = servletName.trim();
957
                this.resourceOnlyServlets.add(servletName);
958
            if (servletName.length()>0) {
958
            }
959
                this.resourceOnlyServlets.add(servletName);
959
        }
960
            }
960
    }
961
        }
961
962
    }
962
963
963
    @Override
964
964
    public boolean isResourceOnlyServlet(String servletName) {
965
    @Override
965
        return resourceOnlyServlets.contains(servletName);
966
    public boolean isResourceOnlyServlet(String servletName) {
966
    }
967
        return resourceOnlyServlets.contains(servletName);
967
968
    }
968
969
969
    @Override
970
970
    public int getEffectiveMajorVersion() {
971
    @Override
971
        return effectiveMajorVersion;
972
    public int getEffectiveMajorVersion() {
972
    }
973
        return effectiveMajorVersion;
973
974
    }
974
    @Override
975
975
    public void setEffectiveMajorVersion(int effectiveMajorVersion) {
976
    @Override
976
        this.effectiveMajorVersion = effectiveMajorVersion;
977
    public void setEffectiveMajorVersion(int effectiveMajorVersion) {
977
    }
978
        this.effectiveMajorVersion = effectiveMajorVersion;
978
979
    }
979
    @Override
980
980
    public int getEffectiveMinorVersion() {
981
    @Override
981
        return effectiveMinorVersion;
982
    public int getEffectiveMinorVersion() {
982
    }
983
        return effectiveMinorVersion;
983
984
    }
984
    @Override
985
985
    public void setEffectiveMinorVersion(int effectiveMinorVersion) {
986
    @Override
986
        this.effectiveMinorVersion = effectiveMinorVersion;
987
    public void setEffectiveMinorVersion(int effectiveMinorVersion) {
987
    }
988
        this.effectiveMinorVersion = effectiveMinorVersion;
988
    
989
    }
989
    @Override
990
    
990
    public void setLogEffectiveWebXml(boolean logEffectiveWebXml) {
991
    @Override
991
        this.logEffectiveWebXml = logEffectiveWebXml;
992
    public void setLogEffectiveWebXml(boolean logEffectiveWebXml) {
992
    }
993
        this.logEffectiveWebXml = logEffectiveWebXml;
993
    
994
    }
994
    @Override
995
    
995
    public boolean getLogEffectiveWebXml() {
996
    @Override
996
        return logEffectiveWebXml;
997
    public boolean getLogEffectiveWebXml() {
997
    }
998
        return logEffectiveWebXml;
998
999
    }
999
    @Override
1000
1000
    public Authenticator getAuthenticator() {
1001
    @Override
1001
        if (this instanceof Authenticator)
1002
    public Authenticator getAuthenticator() {
1002
            return (Authenticator) this;
1003
        if (this instanceof Authenticator)
1003
        
1004
            return (Authenticator) this;
1004
        Pipeline pipeline = getPipeline();
1005
        
1005
        if (pipeline != null) {
1006
        Pipeline pipeline = getPipeline();
1006
            Valve basic = pipeline.getBasic();
1007
        if (pipeline != null) {
1007
            if ((basic != null) && (basic instanceof Authenticator))
1008
            Valve basic = pipeline.getBasic();
1008
                return (Authenticator) basic;
1009
            if ((basic != null) && (basic instanceof Authenticator))
1009
            Valve valves[] = pipeline.getValves();
1010
                return (Authenticator) basic;
1010
            for (int i = 0; i < valves.length; i++) {
1011
            Valve valves[] = pipeline.getValves();
1011
                if (valves[i] instanceof Authenticator)
1012
            for (int i = 0; i < valves.length; i++) {
1012
                    return (Authenticator) valves[i];
1013
                if (valves[i] instanceof Authenticator)
1013
            }
1014
                    return (Authenticator) valves[i];
1014
        }
1015
            }
1015
        return null;
1016
        }
1016
    }
1017
        return null;
1017
    
1018
    }
1018
    @Override
1019
    
1019
    public JarScanner getJarScanner() {
1020
    @Override
1020
        if (jarScanner == null) {
1021
    public JarScanner getJarScanner() {
1021
            jarScanner = new StandardJarScanner();
1022
        if (jarScanner == null) {
1022
        }
1023
            jarScanner = new StandardJarScanner();
1023
        return jarScanner;
1024
        }
1024
    }
1025
        return jarScanner;
1025
1026
    }
1026
1027
1027
    @Override
1028
1028
    public void setJarScanner(JarScanner jarScanner) {
1029
    @Override
1029
        this.jarScanner = jarScanner;
1030
    public void setJarScanner(JarScanner jarScanner) {
1030
    }
1031
        this.jarScanner = jarScanner;
1031
1032
    }
1032
     
1033
1033
    public InstanceManager getInstanceManager() {
1034
     
1034
       return instanceManager;
1035
    public InstanceManager getInstanceManager() {
1035
    }
1036
       return instanceManager;
1036
1037
    }
1037
1038
1038
    public void setInstanceManager(InstanceManager instanceManager) {
1039
1039
       this.instanceManager = instanceManager;
1040
    public void setInstanceManager(InstanceManager instanceManager) {
1040
    }
1041
       this.instanceManager = instanceManager;
1041
1042
    }
1042
    
1043
1043
    @Override
1044
    
1044
    public String getEncodedPath() {
1045
    @Override
1045
        return encodedPath;
1046
    public String getEncodedPath() {
1046
    }
1047
        return encodedPath;
1047
1048
    }
1048
1049
1049
    /**
1050
1050
     * Is caching allowed ?
1051
    /**
1051
     */
1052
     * Is caching allowed ?
1052
    public boolean isCachingAllowed() {
1053
     */
1053
        return cachingAllowed;
1054
    public boolean isCachingAllowed() {
1054
    }
1055
        return cachingAllowed;
1055
1056
    }
1056
1057
1057
    /**
1058
1058
     * Set caching allowed flag.
1059
    /**
1059
     */
1060
     * Set caching allowed flag.
1060
    public void setCachingAllowed(boolean cachingAllowed) {
1061
     */
1061
        this.cachingAllowed = cachingAllowed;
1062
    public void setCachingAllowed(boolean cachingAllowed) {
1062
    }
1063
        this.cachingAllowed = cachingAllowed;
1063
1064
    }
1064
1065
1065
    /**
1066
1066
     * Set allow linking.
1067
    /**
1067
     */
1068
     * Set allow linking.
1068
    public void setAllowLinking(boolean allowLinking) {
1069
     */
1069
        this.allowLinking = allowLinking;
1070
    public void setAllowLinking(boolean allowLinking) {
1070
    }
1071
        this.allowLinking = allowLinking;
1071
1072
    }
1072
1073
1073
    /**
1074
1074
     * Is linking allowed.
1075
    /**
1075
     */
1076
     * Is linking allowed.
1076
    public boolean isAllowLinking() {
1077
     */
1077
        return allowLinking;
1078
    public boolean isAllowLinking() {
1078
    }
1079
        return allowLinking;
1079
1080
    }
1080
    /**
1081
1081
     * Set to <code>true</code> to allow requests mapped to servlets that
1082
    /**
1082
     * do not explicitly declare @MultipartConfig or have
1083
     * Set to <code>true</code> to allow requests mapped to servlets that
1083
     * &lt;multipart-config&gt; specified in web.xml to parse
1084
     * do not explicitly declare @MultipartConfig or have
1084
     * multipart/form-data requests.
1085
     * &lt;multipart-config&gt; specified in web.xml to parse
1085
     *
1086
     * multipart/form-data requests.
1086
     * @param allowCasualMultipartParsing <code>true</code> to allow such
1087
     *
1087
     *        casual parsing, <code>false</code> otherwise.
1088
     * @param allowCasualMultipartParsing <code>true</code> to allow such
1088
     */
1089
     *        casual parsing, <code>false</code> otherwise.
1089
    @Override
1090
     */
1090
    public void setAllowCasualMultipartParsing(
1091
    @Override
1091
            boolean allowCasualMultipartParsing) {
1092
    public void setAllowCasualMultipartParsing(
1092
        this.allowCasualMultipartParsing = allowCasualMultipartParsing;
1093
            boolean allowCasualMultipartParsing) {
1093
    }
1094
        this.allowCasualMultipartParsing = allowCasualMultipartParsing;
1094
1095
    }
1095
    /**
1096
1096
     * Returns <code>true</code> if requests mapped to servlets without
1097
    /**
1097
     * "multipart config" to parse multipart/form-data requests anyway.
1098
     * Returns <code>true</code> if requests mapped to servlets without
1098
     *
1099
     * "multipart config" to parse multipart/form-data requests anyway.
1099
     * @return <code>true</code> if requests mapped to servlets without
1100
     *
1100
     *    "multipart config" to parse multipart/form-data requests,
1101
     * @return <code>true</code> if requests mapped to servlets without
1101
     *    <code>false</code> otherwise.
1102
     *    "multipart config" to parse multipart/form-data requests,
1102
     */
1103
     *    <code>false</code> otherwise.
1103
    @Override
1104
     */
1104
    public boolean getAllowCasualMultipartParsing() {
1105
    @Override
1105
        return this.allowCasualMultipartParsing;
1106
    public boolean getAllowCasualMultipartParsing() {
1106
    }
1107
        return this.allowCasualMultipartParsing;
1107
1108
    }
1108
    /**
1109
1109
     * Set to <code>false</code> to disable request data swallowing
1110
    /**
1110
     * after an upload was aborted due to size constraints.
1111
     * Set to <code>false</code> to disable request data swallowing
1111
     *
1112
     * after an upload was aborted due to size constraints.
1112
     * @param swallowAbortedUploads <code>false</code> to disable
1113
     *
1113
     *        swallowing, <code>true</code> otherwise (default).
1114
     * @param swallowAbortedUploads <code>false</code> to disable
1114
     */
1115
     *        swallowing, <code>true</code> otherwise (default).
1115
    @Override
1116
     */
1116
    public void setSwallowAbortedUploads(boolean swallowAbortedUploads) {
1117
    @Override
1117
        this.swallowAbortedUploads = swallowAbortedUploads;
1118
    public void setSwallowAbortedUploads(boolean swallowAbortedUploads) {
1118
    }
1119
        this.swallowAbortedUploads = swallowAbortedUploads;
1119
1120
    }
1120
    /**
1121
1121
     * Returns <code>true</code> if remaining request data will be read
1122
    /**
1122
     * (swallowed) even the request violates a data size constraint.
1123
     * Returns <code>true</code> if remaining request data will be read
1123
     *
1124
     * (swallowed) even the request violates a data size constraint.
1124
     * @return <code>true</code> if data will be swallowed (default),
1125
     *
1125
     *    <code>false</code> otherwise.
1126
     * @return <code>true</code> if data will be swallowed (default),
1126
     */
1127
     *    <code>false</code> otherwise.
1127
    @Override
1128
     */
1128
    public boolean getSwallowAbortedUploads() {
1129
    @Override
1129
        return this.swallowAbortedUploads;
1130
    public boolean getSwallowAbortedUploads() {
1130
    }
1131
        return this.swallowAbortedUploads;
1131
1132
    }
1132
    /**
1133
1133
     * Set cache TTL.
1134
    /**
1134
     */
1135
     * Set cache TTL.
1135
    public void setCacheTTL(int cacheTTL) {
1136
     */
1136
        this.cacheTTL = cacheTTL;
1137
    public void setCacheTTL(int cacheTTL) {
1137
    }
1138
        this.cacheTTL = cacheTTL;
1138
1139
    }
1139
1140
1140
    /**
1141
1141
     * Get cache TTL.
1142
    /**
1142
     */
1143
     * Get cache TTL.
1143
    public int getCacheTTL() {
1144
     */
1144
        return cacheTTL;
1145
    public int getCacheTTL() {
1145
    }
1146
        return cacheTTL;
1146
1147
    }
1147
1148
1148
    /**
1149
1149
     * Return the maximum size of the cache in KB.
1150
    /**
1150
     */
1151
     * Return the maximum size of the cache in KB.
1151
    public int getCacheMaxSize() {
1152
     */
1152
        return cacheMaxSize;
1153
    public int getCacheMaxSize() {
1153
    }
1154
        return cacheMaxSize;
1154
1155
    }
1155
1156
1156
    /**
1157
1157
     * Set the maximum size of the cache in KB.
1158
    /**
1158
     */
1159
     * Set the maximum size of the cache in KB.
1159
    public void setCacheMaxSize(int cacheMaxSize) {
1160
     */
1160
        this.cacheMaxSize = cacheMaxSize;
1161
    public void setCacheMaxSize(int cacheMaxSize) {
1161
    }
1162
        this.cacheMaxSize = cacheMaxSize;
1162
1163
    }
1163
1164
1164
    /**
1165
1165
     * Return the maximum size of objects to be cached in KB.
1166
    /**
1166
     */
1167
     * Return the maximum size of objects to be cached in KB.
1167
    public int getCacheObjectMaxSize() {
1168
     */
1168
        return cacheObjectMaxSize;
1169
    public int getCacheObjectMaxSize() {
1169
    }
1170
        return cacheObjectMaxSize;
1170
1171
    }
1171
1172
1172
    /**
1173
1173
     * Set the maximum size of objects to be placed the cache in KB.
1174
    /**
1174
     */
1175
     * Set the maximum size of objects to be placed the cache in KB.
1175
    public void setCacheObjectMaxSize(int cacheObjectMaxSize) {
1176
     */
1176
        this.cacheObjectMaxSize = cacheObjectMaxSize;
1177
    public void setCacheObjectMaxSize(int cacheObjectMaxSize) {
1177
    }
1178
        this.cacheObjectMaxSize = cacheObjectMaxSize;
1178
1179
    }
1179
1180
1180
    /**
1181
1181
     * Return the list of resource aliases. 
1182
    /**
1182
     */
1183
     * Return the list of resource aliases. 
1183
    public String getAliases() {
1184
     */
1184
        return this.aliases;
1185
    public String getAliases() {
1185
    }
1186
        return this.aliases;
1186
1187
    }
1187
1188
1188
    /**
1189
1189
     * Add a URL for a JAR that contains static resources in a
1190
    /**
1190
     * META-INF/resources directory that should be included in the static
1191
     * Add a URL for a JAR that contains static resources in a
1191
     * resources for this context.
1192
     * META-INF/resources directory that should be included in the static
1192
     */
1193
     * resources for this context.
1193
    @Override
1194
     */
1194
    public void addResourceJarUrl(URL url) {
1195
    @Override
1195
        if (webappResources instanceof BaseDirContext) {
1196
    public void addResourceJarUrl(URL url) {
1196
            ((BaseDirContext) webappResources).addResourcesJar(url);
1197
        if (webappResources instanceof BaseDirContext) {