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

(-)java/org/apache/catalina/Container.java (+17 lines)
Lines 476-479 Link Here
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
    
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);
479
}
496
}
(-)java/org/apache/catalina/Host.java (-1 / +9 lines)
Lines 17-22 Link Here
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.concurrent.ExecutorService;
20
import java.util.regex.Pattern;
21
import java.util.regex.Pattern;
21
22
22
23
Lines 180-188 Link Here
180
    public void setDeployIgnore(String deployIgnore);
181
    public void setDeployIgnore(String deployIgnore);
181
182
182
183
184
    /**
185
     * Return the executor that is used for starting and stopping contexts. This
186
     * is primarily for use by components deploying contexts that want to do
187
     * this in a multi-threaded manner.
188
     */
189
    public ExecutorService getStartStopExecutor();
190
    
191
    
183
    // --------------------------------------------------------- Public Methods
192
    // --------------------------------------------------------- Public Methods
184
193
185
186
    /**
194
    /**
187
     * Add an alias name that should be mapped to this same Host.
195
     * Add an alias name that should be mapped to this same Host.
188
     *
196
     *
(-)java/org/apache/catalina/core/ContainerBase.java (-2 / +135 lines)
Lines 26-31 Link Here
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
import java.util.List;
30
import java.util.concurrent.BlockingQueue;
31
import java.util.concurrent.Callable;
32
import java.util.concurrent.Future;
33
import java.util.concurrent.LinkedBlockingQueue;
34
import java.util.concurrent.ThreadPoolExecutor;
35
import java.util.concurrent.TimeUnit;
29
36
30
import javax.management.ObjectName;
37
import javax.management.ObjectName;
31
import javax.naming.directory.DirContext;
38
import javax.naming.directory.DirContext;
Lines 274-283 Link Here
274
    protected volatile AccessLog accessLog = null;
281
    protected volatile AccessLog accessLog = null;
275
    private volatile boolean accessLogScanComplete = false;
282
    private volatile boolean accessLogScanComplete = false;
276
283
284
285
    /**
286
     * The number of threads available to process start and stop events for any
287
     * children associated with this container.
288
     */
289
    private int startStopThreads = 1;
290
    protected ThreadPoolExecutor startStopExecutor;
291
    
277
    // ------------------------------------------------------------- Properties
292
    // ------------------------------------------------------------- Properties
278
293
294
    @Override
295
    public int getStartStopThreads() {
296
        return startStopThreads;
297
    }
279
298
280
    /**
299
    /**
300
     * Handles the special values.
301
     */
302
    private int getStartStopThreadsInternal() {
303
        int result = getStartStopThreads();
304
        
305
        // Positive values are unchanged 
306
        if (result > 0) {
307
            return result;
308
        }
309
        
310
        // Zero == Runtime.getRuntime().availableProcessors()
311
        // -ve  == Runtime.getRuntime().availableProcessors() + value
312
        // These two are the same
313
        result = Runtime.getRuntime().availableProcessors() + result;
314
        if (result < 1) {
315
            result = 1;
316
        }
317
        return result;
318
    }
319
320
    @Override
321
    public void setStartStopThreads(int startStopThreads) {
322
        this.startStopThreads = startStopThreads;
323
        
324
        // Use local copies to ensure thread safety
325
        ThreadPoolExecutor executor = startStopExecutor;
326
        if (executor != null) {
327
            int newThreads = getStartStopThreadsInternal();
328
            executor.setMaximumPoolSize(newThreads);
329
            executor.setCorePoolSize(newThreads);
330
        }
331
    }
332
333
334
    /**
281
     * Get the delay between the invocation of the backgroundProcess method on
335
     * Get the delay between the invocation of the backgroundProcess method on
282
     * this container and its children. Child containers will not be invoked
336
     * this container and its children. Child containers will not be invoked
283
     * if their delay value is not negative (which would mean they are using 
337
     * if their delay value is not negative (which would mean they are using 
Lines 1001-1006 Link Here
1001
    }
1055
    }
1002
1056
1003
1057
1058
    @Override
1059
    protected void initInternal() throws LifecycleException {
1060
        BlockingQueue<Runnable> startStopQueue =
1061
            new LinkedBlockingQueue<Runnable>();
1062
        startStopExecutor = new ThreadPoolExecutor(
1063
                getStartStopThreadsInternal(),
1064
                getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
1065
                startStopQueue);
1066
        // Allow executor thread pool size to drop to zero if not required
1067
        startStopExecutor.allowCoreThreadTimeOut(true);
1068
        super.initInternal();
1069
    }
1070
1071
1004
    /**
1072
    /**
1005
     * Start this component and implement the requirements
1073
     * Start this component and implement the requirements
1006
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
1074
     * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
Lines 1029-1037 Link Here
1029
1097
1030
        // Start our child containers, if any
1098
        // Start our child containers, if any
1031
        Container children[] = findChildren();
1099
        Container children[] = findChildren();
1100
        List<Future<Void>> results = new ArrayList<Future<Void>>();
1032
        for (int i = 0; i < children.length; i++) {
1101
        for (int i = 0; i < children.length; i++) {
1033
            children[i].start();
1102
            results.add(startStopExecutor.submit(new StartChild(children[i])));
1034
        }
1103
        }
1104
        Iterator<Future<Void>> iter = results.iterator();
1105
        boolean fail = false;
1106
        while (iter.hasNext()) {
1107
            try {
1108
                iter.next().get();
1109
            } catch (Exception e) {
1110
                // TODO Log this
1111
                fail = true;
1112
            }
1113
        }
1114
        if (fail) {
1115
            // TODO Add a useful message
1116
            throw new LifecycleException();
1117
        }
1035
1118
1036
        // Start the Valves in our pipeline (including the basic), if any
1119
        // Start the Valves in our pipeline (including the basic), if any
1037
        if (pipeline instanceof Lifecycle)
1120
        if (pipeline instanceof Lifecycle)
Lines 1069-1077 Link Here
1069
1152
1070
        // Stop our child containers, if any
1153
        // Stop our child containers, if any
1071
        Container children[] = findChildren();
1154
        Container children[] = findChildren();
1155
        List<Future<Void>> results = new ArrayList<Future<Void>>();
1072
        for (int i = 0; i < children.length; i++) {
1156
        for (int i = 0; i < children.length; i++) {
1073
            children[i].stop();
1157
            results.add(startStopExecutor.submit(new StopChild(children[i])));
1074
        }
1158
        }
1159
        Iterator<Future<Void>> iter = results.iterator();
1160
        boolean fail = false;
1161
        while (iter.hasNext()) {
1162
            try {
1163
                iter.next().get();
1164
            } catch (Exception e) {
1165
                // TODO Log this
1166
                fail = true;
1167
            }
1168
        }
1169
        if (fail) {
1170
            // TODO Add a useful message
1171
            throw new LifecycleException();
1172
        }
1075
1173
1076
        // Stop our subordinate components, if any
1174
        // Stop our subordinate components, if any
1077
        if ((resources != null) && (resources instanceof Lifecycle)) {
1175
        if ((resources != null) && (resources instanceof Lifecycle)) {
Lines 1113-1118 Link Here
1113
            parent.removeChild(this);
1211
            parent.removeChild(this);
1114
        }
1212
        }
1115
1213
1214
        startStopExecutor.shutdownNow();
1215
1116
        super.destroyInternal();
1216
        super.destroyInternal();
1117
    }
1217
    }
1118
1218
Lines 1412-1415 Link Here
1412
            }
1512
            }
1413
        }
1513
        }
1414
    }
1514
    }
1515
    
1516
    
1517
    // ----------------------------- Inner classes used with start/stop Executor
1518
    
1519
    private static class StartChild implements Callable<Void> {
1520
1521
        private Container child;
1522
        
1523
        public StartChild(Container child) {
1524
            this.child = child;
1525
        }
1526
1527
        @Override
1528
        public Void call() throws LifecycleException {
1529
            child.start();
1530
            return null;
1531
        }
1532
    }
1533
1534
    private static class StopChild implements Callable<Void> {
1535
1536
        private Container child;
1537
        
1538
        public StopChild(Container child) {
1539
            this.child = child;
1540
        }
1541
1542
        @Override
1543
        public Void call() throws LifecycleException {
1544
            child.stop();
1545
            return null;
1546
        }
1547
    }
1415
}
1548
}
(-)java/org/apache/catalina/core/StandardHost.java (-1 / +7 lines)
Lines 24-29 Link Here
24
import java.util.Locale;
24
import java.util.Locale;
25
import java.util.Map;
25
import java.util.Map;
26
import java.util.WeakHashMap;
26
import java.util.WeakHashMap;
27
import java.util.concurrent.ExecutorService;
27
import java.util.regex.Pattern;
28
import java.util.regex.Pattern;
28
29
29
import org.apache.catalina.Container;
30
import org.apache.catalina.Container;
Lines 183-190 Link Here
183
184
184
    // ------------------------------------------------------------- Properties
185
    // ------------------------------------------------------------- Properties
185
186
187
     @Override
188
     public ExecutorService getStartStopExecutor() {
189
         return startStopExecutor;
190
     }
186
191
187
    /**
192
193
     /**
188
     * Return the application root for this Host.  This can be an absolute
194
     * Return the application root for this Host.  This can be an absolute
189
     * pathname, a relative pathname, or a URL.
195
     * pathname, a relative pathname, or a URL.
190
     */
196
     */
(-)java/org/apache/catalina/core/mbeans-descriptors.xml (+8 lines)
Lines 1011-1016 Link Here
1011
               description="Will children be started automatically when they are added."
1011
               description="Will children be started automatically when they are added."
1012
               type="boolean"/>  
1012
               type="boolean"/>  
1013
1013
1014
    <attribute name="startStopThreads"
1015
               description="The number of threads to use when starting and stopping child Hosts"
1016
               type="int"/>            
1017
1014
    <attribute name="stateName"
1018
    <attribute name="stateName"
1015
               description="The name of the LifecycleState that this component is currently in"
1019
               description="The name of the LifecycleState that this component is currently in"
1016
               type="java.lang.String"
1020
               type="java.lang.String"
Lines 1198-1203 Link Here
1198
               description="Will children be started automatically when they are added?"
1202
               description="Will children be started automatically when they are added?"
1199
               type="boolean"/>            
1203
               type="boolean"/>            
1200
1204
1205
    <attribute name="startStopThreads"
1206
               description="The number of threads to use when starting, stopping and deploying child Contexts"
1207
               type="int"/>            
1208
1201
    <attribute name="stateName"
1209
    <attribute name="stateName"
1202
               description="The name of the LifecycleState that this component is currently in"
1210
               description="The name of the LifecycleState that this component is currently in"
1203
               type="java.lang.String"
1211
               type="java.lang.String"
(-)java/org/apache/catalina/startup/ContextConfig.java (-162 / +82 lines)
Lines 125-136 Link Here
125
    protected static final LoginConfig DUMMY_LOGIN_CONFIG =
125
    protected static final LoginConfig DUMMY_LOGIN_CONFIG =
126
        new LoginConfig("NONE", null, null, null);
126
        new LoginConfig("NONE", null, null, null);
127
127
128
    /**
129
     * The <code>Digester</code> we will use to process web application
130
     * context files.
131
     */
132
    protected static Digester contextDigester = null;
133
    
134
128
135
    /**
129
    /**
136
     * The set of Authenticators that we know how to configure.  The key is
130
     * The set of Authenticators that we know how to configure.  The key is
Lines 141-172 Link Here
141
135
142
136
143
    /**
137
    /**
144
     * The <code>Digester</code>s available to process web deployment descriptor
145
     * files.
146
     */
147
    protected static Digester[] webDigesters = new Digester[4];
148
149
150
    /**
151
     * The <code>Digester</code>s available to process web fragment deployment
152
     * descriptor files.
153
     */
154
    protected static Digester[] webFragmentDigesters = new Digester[4];
155
156
157
    /**
158
     * The <code>Rule</code>s used to parse the web.xml
159
     */
160
    protected static WebRuleSet webRuleSet = new WebRuleSet(false);
161
162
163
    /**
164
     * The <code>Rule</code>s used to parse the web-fragment.xml
165
     */
166
    protected static WebRuleSet webFragmentRuleSet = new WebRuleSet(true);
167
168
169
    /**
170
     * Deployment count.
138
     * Deployment count.
171
     */
139
     */
172
    protected static long deploymentCount = 0L;
140
    protected static long deploymentCount = 0L;
Lines 227-238 Link Here
227
     * deployment descriptor files.
195
     * deployment descriptor files.
228
     */
196
     */
229
    protected Digester webDigester = null;
197
    protected Digester webDigester = null;
198
    protected WebRuleSet webRuleSet = null;
230
199
231
    /**
200
    /**
232
     * The <code>Digester</code> we will use to process web fragment
201
     * The <code>Digester</code> we will use to process web fragment
233
     * deployment descriptor files.
202
     * deployment descriptor files.
234
     */
203
     */
235
    protected Digester webFragmentDigester = null;
204
    protected Digester webFragmentDigester = null;
205
    protected WebRuleSet webFragmentRuleSet = null;
236
206
237
    
207
    
238
    // ------------------------------------------------------------- Properties
208
    // ------------------------------------------------------------- Properties
Lines 476-535 Link Here
476
446
477
447
478
    /**
448
    /**
479
     * Create (if necessary) and return a Digester configured to process the
449
     * Create and return a Digester configured to process the
480
     * web application deployment descriptor (web.xml).
450
     * web application deployment descriptor (web.xml).
481
     */
451
     */
482
    public void createWebXmlDigester(boolean namespaceAware,
452
    public void createWebXmlDigester(boolean namespaceAware,
483
            boolean validation) {
453
            boolean validation) {
484
        
454
        
485
        if (!namespaceAware && !validation) {
455
        webRuleSet = new WebRuleSet(false);
486
            if (webDigesters[0] == null) {
456
        webDigester = DigesterFactory.newDigester(validation,
487
                webDigesters[0] = DigesterFactory.newDigester(validation,
457
                namespaceAware, webRuleSet);
488
                        namespaceAware, webRuleSet);
458
        webDigester.getParser();
489
                webFragmentDigesters[0] = DigesterFactory.newDigester(validation,
459
        
490
                        namespaceAware, webFragmentRuleSet);
460
        webFragmentRuleSet = new WebRuleSet(true);
491
                webDigesters[0].getParser();
461
        webFragmentDigester = DigesterFactory.newDigester(validation,
492
                webFragmentDigesters[0].getParser();
462
                namespaceAware, webFragmentRuleSet);
493
            }
463
        webFragmentDigester.getParser();
494
            webDigester = webDigesters[0];
495
            webFragmentDigester = webFragmentDigesters[0];
496
            
497
        } else if (!namespaceAware && validation) {
498
            if (webDigesters[1] == null) {
499
                webDigesters[1] = DigesterFactory.newDigester(validation,
500
                        namespaceAware, webRuleSet);
501
                webFragmentDigesters[1] = DigesterFactory.newDigester(validation,
502
                        namespaceAware, webFragmentRuleSet);
503
                webDigesters[1].getParser();
504
                webFragmentDigesters[1].getParser();
505
            }
506
            webDigester = webDigesters[1];
507
            webFragmentDigester = webFragmentDigesters[1];
508
            
509
        } else if (namespaceAware && !validation) {
510
            if (webDigesters[2] == null) {
511
                webDigesters[2] = DigesterFactory.newDigester(validation,
512
                        namespaceAware, webRuleSet);
513
                webFragmentDigesters[2] = DigesterFactory.newDigester(validation,
514
                        namespaceAware, webFragmentRuleSet);
515
                webDigesters[2].getParser();
516
                webFragmentDigesters[2].getParser();
517
            }
518
            webDigester = webDigesters[2];
519
            webFragmentDigester = webFragmentDigesters[2];
520
            
521
        } else {
522
            if (webDigesters[3] == null) {
523
                webDigesters[3] = DigesterFactory.newDigester(validation,
524
                        namespaceAware, webRuleSet);
525
                webFragmentDigesters[3] = DigesterFactory.newDigester(validation,
526
                        namespaceAware, webFragmentRuleSet);
527
                webDigesters[3].getParser();
528
                webFragmentDigesters[3].getParser();
529
            }
530
            webDigester = webDigesters[3];
531
            webFragmentDigester = webFragmentDigesters[3];
532
        }
533
    }
464
    }
534
465
535
    
466
    
Lines 567-573 Link Here
567
    /**
498
    /**
568
     * Process the default configuration file, if it exists.
499
     * Process the default configuration file, if it exists.
569
     */
500
     */
570
    protected void contextConfig() {
501
    protected void contextConfig(Digester digester) {
571
        
502
        
572
        // Open the default context.xml file, if it exists
503
        // Open the default context.xml file, if it exists
573
        if( defaultContextXml==null && context instanceof StandardContext ) {
504
        if( defaultContextXml==null && context instanceof StandardContext ) {
Lines 584-590 Link Here
584
            if (defaultContextFile.exists()) {
515
            if (defaultContextFile.exists()) {
585
                try {
516
                try {
586
                    URL defaultContextUrl = defaultContextFile.toURI().toURL();
517
                    URL defaultContextUrl = defaultContextFile.toURI().toURL();
587
                    processContextConfig(defaultContextUrl);
518
                    processContextConfig(digester, defaultContextUrl);
588
                } catch (MalformedURLException e) {
519
                } catch (MalformedURLException e) {
589
                    log.error(sm.getString(
520
                    log.error(sm.getString(
590
                            "contextConfig.badUrl", defaultContextFile), e);
521
                            "contextConfig.badUrl", defaultContextFile), e);
Lines 596-602 Link Here
596
            if (hostContextFile.exists()) {
527
            if (hostContextFile.exists()) {
597
                try {
528
                try {
598
                    URL hostContextUrl = hostContextFile.toURI().toURL();
529
                    URL hostContextUrl = hostContextFile.toURI().toURL();
599
                    processContextConfig(hostContextUrl);
530
                    processContextConfig(digester, hostContextUrl);
600
                } catch (MalformedURLException e) {
531
                } catch (MalformedURLException e) {
601
                    log.error(sm.getString(
532
                    log.error(sm.getString(
602
                            "contextConfig.badUrl", hostContextFile), e);
533
                            "contextConfig.badUrl", hostContextFile), e);
Lines 604-610 Link Here
604
            }
535
            }
605
        }
536
        }
606
        if (context.getConfigFile() != null)
537
        if (context.getConfigFile() != null)
607
            processContextConfig(context.getConfigFile());
538
            processContextConfig(digester, context.getConfigFile());
608
        
539
        
609
    }
540
    }
610
541
Lines 612-618 Link Here
612
    /**
543
    /**
613
     * Process a context.xml.
544
     * Process a context.xml.
614
     */
545
     */
615
    protected void processContextConfig(URL contextXml) {
546
    protected void processContextConfig(Digester digester, URL contextXml) {
616
        
547
        
617
        if (log.isDebugEnabled())
548
        if (log.isDebugEnabled())
618
            log.debug("Processing context [" + context.getName() 
549
            log.debug("Processing context [" + context.getName() 
Lines 638-681 Link Here
638
        
569
        
639
        if (source == null)
570
        if (source == null)
640
            return;
571
            return;
641
        synchronized (contextDigester) {
572
573
        try {
574
            source.setByteStream(stream);
575
            digester.setClassLoader(this.getClass().getClassLoader());
576
            digester.setUseContextClassLoader(false);
577
            digester.push(context.getParent());
578
            digester.push(context);
579
            XmlErrorHandler errorHandler = new XmlErrorHandler();
580
            digester.setErrorHandler(errorHandler);
581
            digester.parse(source);
582
            if (errorHandler.getWarnings().size() > 0 ||
583
                    errorHandler.getErrors().size() > 0) {
584
                errorHandler.logFindings(log, contextXml.toString());
585
                ok = false;
586
            }
587
            if (log.isDebugEnabled())
588
                log.debug("Successfully processed context [" + context.getName() 
589
                        + "] configuration file [" + contextXml + "]");
590
        } catch (SAXParseException e) {
591
            log.error(sm.getString("contextConfig.contextParse",
592
                    context.getName()), e);
593
            log.error(sm.getString("contextConfig.defaultPosition",
594
                             "" + e.getLineNumber(),
595
                             "" + e.getColumnNumber()));
596
            ok = false;
597
        } catch (Exception e) {
598
            log.error(sm.getString("contextConfig.contextParse",
599
                    context.getName()), e);
600
            ok = false;
601
        } finally {
642
            try {
602
            try {
643
                source.setByteStream(stream);
603
                if (stream != null) {
644
                contextDigester.setClassLoader(this.getClass().getClassLoader());
604
                    stream.close();
645
                contextDigester.setUseContextClassLoader(false);
646
                contextDigester.push(context.getParent());
647
                contextDigester.push(context);
648
                XmlErrorHandler errorHandler = new XmlErrorHandler();
649
                contextDigester.setErrorHandler(errorHandler);
650
                contextDigester.parse(source);
651
                if (errorHandler.getWarnings().size() > 0 ||
652
                        errorHandler.getErrors().size() > 0) {
653
                    errorHandler.logFindings(log, contextXml.toString());
654
                    ok = false;
655
                }
605
                }
656
                if (log.isDebugEnabled())
606
            } catch (IOException e) {
657
                    log.debug("Successfully processed context [" + context.getName() 
607
                log.error(sm.getString("contextConfig.contextClose"), e);
658
                            + "] configuration file [" + contextXml + "]");
659
            } catch (SAXParseException e) {
660
                log.error(sm.getString("contextConfig.contextParse",
661
                        context.getName()), e);
662
                log.error(sm.getString("contextConfig.defaultPosition",
663
                                 "" + e.getLineNumber(),
664
                                 "" + e.getColumnNumber()));
665
                ok = false;
666
            } catch (Exception e) {
667
                log.error(sm.getString("contextConfig.contextParse",
668
                        context.getName()), e);
669
                ok = false;
670
            } finally {
671
                contextDigester.reset();
672
                try {
673
                    if (stream != null) {
674
                        stream.close();
675
                    }
676
                } catch (IOException e) {
677
                    log.error(sm.getString("contextConfig.contextClose"), e);
678
                }
679
            }
608
            }
680
        }
609
        }
681
    }
610
    }
Lines 828-844 Link Here
828
    protected void init() {
757
    protected void init() {
829
        // Called from StandardContext.init()
758
        // Called from StandardContext.init()
830
759
831
        if (contextDigester == null){
760
        Digester contextDigester = createContextDigester();
832
            contextDigester = createContextDigester();
761
        contextDigester.getParser();
833
            contextDigester.getParser();
834
        }
835
762
836
        if (log.isDebugEnabled())
763
        if (log.isDebugEnabled())
837
            log.debug(sm.getString("contextConfig.init"));
764
            log.debug(sm.getString("contextConfig.init"));
838
        context.setConfigured(false);
765
        context.setConfigured(false);
839
        ok = true;
766
        ok = true;
840
        
767
        
841
        contextConfig();
768
        contextConfig(contextDigester);
842
        
769
        
843
        createWebXmlDigester(context.getXmlNamespaceAware(),
770
        createWebXmlDigester(context.getXmlNamespaceAware(),
844
                context.getXmlValidation());
771
                context.getXmlValidation());
Lines 1715-1723 Link Here
1715
1642
1716
        XmlErrorHandler handler = new XmlErrorHandler();
1643
        XmlErrorHandler handler = new XmlErrorHandler();
1717
1644
1718
        // Web digesters and rulesets are shared between contexts but are not
1719
        // thread safe. Whilst there should only be one thread at a time
1720
        // processing a config, play safe and sync.
1721
        Digester digester;
1645
        Digester digester;
1722
        WebRuleSet ruleSet;
1646
        WebRuleSet ruleSet;
1723
        if (fragment) {
1647
        if (fragment) {
Lines 1728-1768 Link Here
1728
            ruleSet = webRuleSet;
1652
            ruleSet = webRuleSet;
1729
        }
1653
        }
1730
        
1654
        
1731
        // Sync on the ruleSet since the same ruleSet is shared across all four
1655
        digester.push(dest);
1732
        // digesters
1656
        digester.setErrorHandler(handler);
1733
        synchronized(ruleSet) {
1657
        
1734
            
1658
        if(log.isDebugEnabled()) {
1735
            digester.push(dest);
1659
            log.debug(sm.getString("contextConfig.applicationStart",
1736
            digester.setErrorHandler(handler);
1660
                    source.getSystemId()));
1737
            
1661
        }
1738
            if(log.isDebugEnabled()) {
1739
                log.debug(sm.getString("contextConfig.applicationStart",
1740
                        source.getSystemId()));
1741
            }
1742
1662
1743
            try {
1663
        try {
1744
                digester.parse(source);
1664
            digester.parse(source);
1745
1665
1746
                if (handler.getWarnings().size() > 0 ||
1666
            if (handler.getWarnings().size() > 0 ||
1747
                        handler.getErrors().size() > 0) {
1667
                    handler.getErrors().size() > 0) {
1748
                    ok = false;
1749
                    handler.logFindings(log, source.getSystemId());
1750
                }
1751
            } catch (SAXParseException e) {
1752
                log.error(sm.getString("contextConfig.applicationParse",
1753
                        source.getSystemId()), e);
1754
                log.error(sm.getString("contextConfig.applicationPosition",
1755
                                 "" + e.getLineNumber(),
1756
                                 "" + e.getColumnNumber()));
1757
                ok = false;
1668
                ok = false;
1758
            } catch (Exception e) {
1669
                handler.logFindings(log, source.getSystemId());
1759
                log.error(sm.getString("contextConfig.applicationParse",
1760
                        source.getSystemId()), e);
1761
                ok = false;
1762
            } finally {
1763
                digester.reset();
1764
                ruleSet.recycle();
1765
            }
1670
            }
1671
        } catch (SAXParseException e) {
1672
            log.error(sm.getString("contextConfig.applicationParse",
1673
                    source.getSystemId()), e);
1674
            log.error(sm.getString("contextConfig.applicationPosition",
1675
                             "" + e.getLineNumber(),
1676
                             "" + e.getColumnNumber()));
1677
            ok = false;
1678
        } catch (Exception e) {
1679
            log.error(sm.getString("contextConfig.applicationParse",
1680
                    source.getSystemId()), e);
1681
            ok = false;
1682
        } finally {
1683
            digester.reset();
1684
            ruleSet.recycle();
1766
        }
1685
        }
1767
    }
1686
    }
1768
1687
Lines 2152-2158 Link Here
2152
2071
2153
    /**
2072
    /**
2154
     * process filter annotation and merge with existing one!
2073
     * process filter annotation and merge with existing one!
2155
     * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet!
2074
     * FIXME: refactoring method too long and has redundant subroutines with
2075
     *        processAnnotationWebServlet!
2156
     * @param className
2076
     * @param className
2157
     * @param ae
2077
     * @param ae
2158
     * @param fragment
2078
     * @param fragment
(-)java/org/apache/catalina/startup/HostConfig.java (-21 / +103 lines)
Lines 14-21 Link Here
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
18
19
package org.apache.catalina.startup;
17
package org.apache.catalina.startup;
20
18
21
19
Lines 30-39 Link Here
30
import java.util.ArrayList;
28
import java.util.ArrayList;
31
import java.util.HashMap;
29
import java.util.HashMap;
32
import java.util.HashSet;
30
import java.util.HashSet;
31
import java.util.Iterator;
33
import java.util.LinkedHashMap;
32
import java.util.LinkedHashMap;
34
import java.util.List;
33
import java.util.List;
35
import java.util.Locale;
34
import java.util.Locale;
36
import java.util.Set;
35
import java.util.Set;
36
import java.util.concurrent.ExecutorService;
37
import java.util.concurrent.Future;
37
import java.util.jar.JarEntry;
38
import java.util.jar.JarEntry;
38
import java.util.jar.JarFile;
39
import java.util.jar.JarFile;
39
import java.util.regex.Matcher;
40
import java.util.regex.Matcher;
Lines 520-538 Link Here
520
        if (files == null)
521
        if (files == null)
521
            return;
522
            return;
522
        
523
        
524
        ExecutorService es = host.getStartStopExecutor();
525
        List<Future<?>> results = new ArrayList<Future<?>>();
526
523
        for (int i = 0; i < files.length; i++) {
527
        for (int i = 0; i < files.length; i++) {
524
            File contextXml = new File(configBase, files[i]);
528
            File contextXml = new File(configBase, files[i]);
525
529
526
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
530
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
527
                ContextName cn = new ContextName(files[i]);
531
                ContextName cn = new ContextName(files[i]);
528
                String name = cn.getName();
529
532
530
                if (isServiced(name))
533
                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
531
                    continue;
534
                    continue;
532
                
535
                
533
                deployDescriptor(cn, contextXml);
536
                results.add(
537
                        es.submit(new DeployDescriptor(this, cn, contextXml)));
534
            }
538
            }
535
        }
539
        }
540
        
541
        Iterator<Future<?>> iter = results.iterator();
542
        while (iter.hasNext()) {
543
            try {
544
                iter.next().get();
545
            } catch (Exception e) {
546
                // TODO Log this. Should never happen. 
547
            }
548
        }
536
    }
549
    }
537
550
538
551
Lines 541-549 Link Here
541
     * @param contextXml
554
     * @param contextXml
542
     */
555
     */
543
    protected void deployDescriptor(ContextName cn, File contextXml) {
556
    protected void deployDescriptor(ContextName cn, File contextXml) {
544
        if (deploymentExists(cn.getName())) {
545
            return;
546
        }
547
        
557
        
548
        DeployedApplication deployedApp = new DeployedApplication(cn.getName());
558
        DeployedApplication deployedApp = new DeployedApplication(cn.getName());
549
559
Lines 670-683 Link Here
670
        if (files == null)
680
        if (files == null)
671
            return;
681
            return;
672
        
682
        
683
        ExecutorService es = host.getStartStopExecutor();
684
        List<Future<?>> results = new ArrayList<Future<?>>();
685
673
        for (int i = 0; i < files.length; i++) {
686
        for (int i = 0; i < files.length; i++) {
674
            
687
            
675
            if (files[i].equalsIgnoreCase("META-INF"))
688
            if (files[i].equalsIgnoreCase("META-INF"))
676
                continue;
689
                continue;
677
            if (files[i].equalsIgnoreCase("WEB-INF"))
690
            if (files[i].equalsIgnoreCase("WEB-INF"))
678
                continue;
691
                continue;
679
            File dir = new File(appBase, files[i]);
692
            File war = new File(appBase, files[i]);
680
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && dir.isFile()
693
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile()
681
                    && !invalidWars.contains(files[i]) ) {
694
                    && !invalidWars.contains(files[i]) ) {
682
                
695
                
683
                ContextName cn = new ContextName(files[i]);
696
                ContextName cn = new ContextName(files[i]);
Lines 690-701 Link Here
690
                    continue;
703
                    continue;
691
                }
704
                }
692
705
693
                if (isServiced(cn.getName()))
706
                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
694
                    continue;
707
                    continue;
695
                
708
                
696
                deployWAR(cn, dir);
709
                results.add(es.submit(new DeployWar(this, cn, war)));
697
            }
710
            }
698
        }
711
        }
712
        
713
        Iterator<Future<?>> iter = results.iterator();
714
        while (iter.hasNext()) {
715
            try {
716
                iter.next().get();
717
            } catch (Exception e) {
718
                // TODO Log this. Should never happen. 
719
            }
720
        }
699
    }
721
    }
700
722
701
723
Lines 741-749 Link Here
741
     */
763
     */
742
    protected void deployWAR(ContextName cn, File war) {
764
    protected void deployWAR(ContextName cn, File war) {
743
        
765
        
744
        if (deploymentExists(cn.getName()))
745
            return;
746
        
747
        // Checking for a nested /META-INF/context.xml
766
        // Checking for a nested /META-INF/context.xml
748
        JarFile jar = null;
767
        JarFile jar = null;
749
        JarEntry entry = null;
768
        JarEntry entry = null;
Lines 935-940 Link Here
935
        if (files == null)
954
        if (files == null)
936
            return;
955
            return;
937
        
956
        
957
        ExecutorService es = host.getStartStopExecutor();
958
        List<Future<?>> results = new ArrayList<Future<?>>();
959
938
        for (int i = 0; i < files.length; i++) {
960
        for (int i = 0; i < files.length; i++) {
939
961
940
            if (files[i].equalsIgnoreCase("META-INF"))
962
            if (files[i].equalsIgnoreCase("META-INF"))
Lines 945-956 Link Here
945
            if (dir.isDirectory()) {
967
            if (dir.isDirectory()) {
946
                ContextName cn = new ContextName(files[i]);
968
                ContextName cn = new ContextName(files[i]);
947
969
948
                if (isServiced(cn.getName()))
970
                if (isServiced(cn.getName()) || deploymentExists(cn.getName()))
949
                    continue;
971
                    continue;
950
972
951
                deployDirectory(cn, dir);
973
                results.add(es.submit(new DeployDirectory(this, cn, dir)));
952
            }
974
            }
953
        }
975
        }
976
        
977
        Iterator<Future<?>> iter = results.iterator();
978
        while (iter.hasNext()) {
979
            try {
980
                iter.next().get();
981
            } catch (Exception e) {
982
                // TODO Log this. Should never happen. 
983
            }
984
        }
954
    }
985
    }
955
986
956
    
987
    
Lines 960-968 Link Here
960
     */
991
     */
961
    protected void deployDirectory(ContextName cn, File dir) {
992
    protected void deployDirectory(ContextName cn, File dir) {
962
        
993
        
963
        if (deploymentExists(cn.getName()))
964
            return;
965
966
        DeployedApplication deployedApp = new DeployedApplication(cn.getName());
994
        DeployedApplication deployedApp = new DeployedApplication(cn.getName());
967
995
968
        // Deploy the application in this directory
996
        // Deploy the application in this directory
Lines 1450-1456 Link Here
1450
        /**
1478
        /**
1451
         * Instant where the application was last put in service.
1479
         * Instant where the application was last put in service.
1452
         */
1480
         */
1453
     public long timestamp = System.currentTimeMillis();
1481
        public long timestamp = System.currentTimeMillis();
1454
    }
1482
    }
1455
1483
1484
    private static class DeployDescriptor implements Runnable {
1485
1486
        private HostConfig config;
1487
        private ContextName cn;
1488
        private File descriptor;
1489
        
1490
        public DeployDescriptor(HostConfig config, ContextName cn,
1491
                File descriptor) {
1492
            this.config = config;
1493
            this.cn = cn;
1494
            this.descriptor= descriptor;
1495
        }
1496
1497
        @Override
1498
        public void run() {
1499
            config.deployDescriptor(cn, descriptor);
1500
        }
1501
    }
1502
1503
    private static class DeployWar implements Runnable {
1504
1505
        private HostConfig config;
1506
        private ContextName cn;
1507
        private File war;
1508
        
1509
        public DeployWar(HostConfig config, ContextName cn, File war) {
1510
            this.config = config;
1511
            this.cn = cn;
1512
            this.war = war;
1513
        }
1514
1515
        @Override
1516
        public void run() {
1517
            config.deployWAR(cn, war);
1518
        }
1519
    }
1520
1521
    private static class DeployDirectory implements Runnable {
1522
1523
        private HostConfig config;
1524
        private ContextName cn;
1525
        private File dir;
1526
        
1527
        public DeployDirectory(HostConfig config, ContextName cn, File dir) {
1528
            this.config = config;
1529
            this.cn = cn;
1530
            this.dir = dir;
1531
        }
1532
1533
        @Override
1534
        public void run() {
1535
            config.deployDirectory(cn, dir);
1536
        }
1537
    }
1456
}
1538
}
(-)webapps/docs/config/engine.xml (+11 lines)
Lines 102-107 Link Here
102
        name.</em></p>
102
        name.</em></p>
103
      </attribute>
103
      </attribute>
104
104
105
      <attribute name="startStopThreads" required="false">
106
        <p>The number of threads this <strong>Engine</strong> will use to start
107
        child <a href="host.html">Host</a> elements in parallel. If not
108
        specified, the default value of 1 will be used. The special value of 0
109
        will result in the value of
110
        <code>Runtime.getRuntime().availableProcessors()</code> being used.
111
        Negative values will result in
112
        <code>Runtime.getRuntime().availableProcessors() + value</code> being
113
        used unless this is less than 1 in which case 1 thread will be used.</p>
114
      </attribute>
115
105
    </attributes>
116
    </attributes>
106
117
107
  </subsection>
118
  </subsection>
(-)webapps/docs/config/host.xml (+13 lines)
Lines 188-193 Link Here
188
        virtual host.</p>
188
        virtual host.</p>
189
      </attribute>
189
      </attribute>
190
190
191
      <attribute name="startStopThreads" required="false">
192
        <p>The number of threads this <strong>Host</strong> will use to start
193
        child <a href="context.html">Context</a> elements in parallel. The same
194
        thread pool will be used to deploy new
195
        <a href="context.html">Context</a>s if automatic deployment is being
196
        used. If not specified, the default value of 1 will be used. The special
197
        value of 0 will result in the value of
198
        <code>Runtime.getRuntime().availableProcessors()</code> being used.
199
        Negative values will result in
200
        <code>Runtime.getRuntime().availableProcessors() + value</code> being
201
        used unless this is less than 1 in which case 1 thread will be used.</p>
202
      </attribute>
203
191
    </attributes>
204
    </attributes>
192
205
193
  </subsection>
206
  </subsection>

Return to bug 46264