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

(-)a/java/org/apache/catalina/Host.java (+4 lines)
Lines 216-220 public interface Host extends Container { Link Here
216
     * @param createDirs
216
     * @param createDirs
217
     */
217
     */
218
    public void setCreateDirs(boolean createDirs);
218
    public void setCreateDirs(boolean createDirs);
219
    
220
    public void setStartupConcurrency(int count);
221
    
222
    public int getStartupConcurrency();
219
223
220
}
224
}
(-)a/java/org/apache/catalina/core/StandardHost.java (+11 lines)
Lines 180-185 public class StandardHost extends ContainerBase implements Host { Link Here
180
      */
180
      */
181
     private Pattern deployIgnore = null;
181
     private Pattern deployIgnore = null;
182
182
183
    private int startupConcurrency;
184
183
185
184
    // ------------------------------------------------------------- Properties
186
    // ------------------------------------------------------------- Properties
185
187
Lines 594-599 public class StandardHost extends ContainerBase implements Host { Link Here
594
                                   deployIgnore);
596
                                   deployIgnore);
595
    }
597
    }
596
598
599
    
600
    public void setStartupConcurrency(int count) {
601
        log.info("Using " + count + " threads for deployment.");
602
        startupConcurrency = count;
603
    }
604
    
605
    public int getStartupConcurrency() {
606
        return startupConcurrency;
607
    }
597
608
598
    // --------------------------------------------------------- Public Methods
609
    // --------------------------------------------------------- Public Methods
599
610
(-)a/java/org/apache/catalina/startup/ContextConfig.java (-3 / +8 lines)
Lines 129-135 public class ContextConfig Link Here
129
     * The <code>Digester</code> we will use to process web application
129
     * The <code>Digester</code> we will use to process web application
130
     * context files.
130
     * context files.
131
     */
131
     */
132
    protected static Digester contextDigester = null;
132
    protected Digester contextDigester = null;
133
    
133
    
134
134
135
    /**
135
    /**
Lines 829-836 public class ContextConfig Link Here
829
        // Called from StandardContext.init()
829
        // Called from StandardContext.init()
830
830
831
        if (contextDigester == null){
831
        if (contextDigester == null){
832
            contextDigester = createContextDigester();
832
            synchronized(this) {
833
            contextDigester.getParser();
833
                if (contextDigester == null) {
834
                    Digester tmpDigester = createContextDigester();
835
                    tmpDigester.getParser();
836
                    contextDigester = tmpDigester;
837
                }
838
            }
834
        }
839
        }
835
840
836
        if (log.isDebugEnabled())
841
        if (log.isDebugEnabled())
(-)a/java/org/apache/catalina/startup/HostConfig.java (-27 / +250 lines)
Lines 28-39 import java.io.InputStream; Link Here
28
import java.io.OutputStream;
28
import java.io.OutputStream;
29
import java.net.URL;
29
import java.net.URL;
30
import java.util.ArrayList;
30
import java.util.ArrayList;
31
import java.util.Collection;
32
import java.util.Collections;
31
import java.util.HashMap;
33
import java.util.HashMap;
32
import java.util.HashSet;
34
import java.util.HashSet;
33
import java.util.LinkedHashMap;
35
import java.util.LinkedHashMap;
34
import java.util.List;
36
import java.util.List;
35
import java.util.Locale;
37
import java.util.Locale;
38
import java.util.Map;
36
import java.util.Set;
39
import java.util.Set;
40
import java.util.concurrent.Callable;
41
import java.util.concurrent.CountDownLatch;
42
import java.util.concurrent.ExecutionException;
43
import java.util.concurrent.Executor;
44
import java.util.concurrent.ExecutorService;
45
import java.util.concurrent.Executors;
46
import java.util.concurrent.Future;
47
import java.util.concurrent.TimeUnit;
48
import java.util.concurrent.TimeoutException;
37
import java.util.jar.JarEntry;
49
import java.util.jar.JarEntry;
38
import java.util.jar.JarFile;
50
import java.util.jar.JarFile;
39
import java.util.regex.Matcher;
51
import java.util.regex.Matcher;
Lines 138-145 public class HostConfig Link Here
138
    /**
150
    /**
139
     * Map of deployed applications.
151
     * Map of deployed applications.
140
     */
152
     */
141
    protected HashMap<String, DeployedApplication> deployed =
153
    protected Map<String, DeployedApplication> deployed = Collections
142
        new HashMap<String, DeployedApplication>();
154
            .synchronizedMap(new HashMap<String, DeployedApplication>());
143
155
144
    
156
    
145
    /**
157
    /**
Lines 160-165 public class HostConfig Link Here
160
     */
172
     */
161
    protected Set<String> invalidWars = new HashSet<String>();
173
    protected Set<String> invalidWars = new HashSet<String>();
162
174
175
    /**
176
     * {@link Executor} to deploy contexts while startup.
177
     */
178
    private ExecutorService deployExecutor;
179
    
163
    // ------------------------------------------------------------- Properties
180
    // ------------------------------------------------------------- Properties
164
181
165
182
Lines 521-541 public class HostConfig Link Here
521
        if (files == null)
538
        if (files == null)
522
            return;
539
            return;
523
        
540
        
524
        for (int i = 0; i < files.length; i++) {
541
        final CountDownLatch deployedLatch = new CountDownLatch(files.length);
525
            File contextXml = new File(configBase, files[i]);
542
        int deployTasks = 0;
543
        
544
        for (final String file: files) {
545
            final File contextXml = new File(configBase, file);
526
546
527
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
547
            if (file.toLowerCase(Locale.ENGLISH).endsWith(".xml")) {
528
                ContextName cn = new ContextName(files[i]);
548
                final ContextName cn = new ContextName(file);
529
                String name = cn.getName();
549
                String name = cn.getName();
530
550
531
                if (isServiced(name))
551
                if (isServiced(name))
532
                    continue;
552
                    continue;
533
                
534
                String file = files[i];
535
553
536
                deployDescriptor(cn, contextXml, file);
554
                deployTasks++;
555
                deployExecutor.execute(new Runnable() {
556
557
                    @Override
558
                    public void run() {
559
                        try {
560
                            deployDescriptor(cn, contextXml, file);
561
                        } finally {
562
                            deployedLatch.countDown();
563
                        }
564
                    }
565
    
566
                });
537
            }
567
            }
538
        }
568
        }
569
570
        for (int i=deployTasks; i<files.length; i++) {
571
            deployedLatch.countDown();
572
        }
573
        try {
574
            deployedLatch.await();
575
        } catch (InterruptedException e) {
576
            log.error(sm.getString("hostConfig.awaitDeployIE"), e);
577
        }
539
    }
578
    }
540
579
541
580
Lines 673-706 public class HostConfig Link Here
673
        if (files == null)
712
        if (files == null)
674
            return;
713
            return;
675
        
714
        
676
        for (int i = 0; i < files.length; i++) {
715
        final CountDownLatch deployedLatch = new CountDownLatch(files.length);
716
        int deployTasks = 0;
717
        
718
        for (final String file: files) {
677
            
719
            
678
            if (files[i].equalsIgnoreCase("META-INF"))
720
            if (file.equalsIgnoreCase("META-INF"))
679
                continue;
721
                continue;
680
            if (files[i].equalsIgnoreCase("WEB-INF"))
722
            if (file.equalsIgnoreCase("WEB-INF"))
681
                continue;
723
                continue;
682
            File dir = new File(appBase, files[i]);
683
            if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && dir.isFile()
684
                    && !invalidWars.contains(files[i]) ) {
685
                
724
                
686
                ContextName cn = new ContextName(files[i]);
725
            final File dir = new File(appBase, file);
726
            if (file.toLowerCase(Locale.ENGLISH).endsWith(".war") && dir.isFile()
727
                    && !invalidWars.contains(file) ) {
728
                
729
                final ContextName cn = new ContextName(file);
687
                
730
                
688
                // Check for WARs with /../ /./ or similar sequences in the name
731
                // Check for WARs with /../ /./ or similar sequences in the name
689
                if (!validateContextPath(appBase, cn.getBaseName())) {
732
                if (!validateContextPath(appBase, cn.getBaseName())) {
690
                    log.error(sm.getString(
733
                    log.error(sm.getString(
691
                            "hostConfig.illegalWarName", files[i]));
734
                            "hostConfig.illegalWarName", file));
692
                    invalidWars.add(files[i]);
735
                    invalidWars.add(file);
693
                    continue;
736
                    continue;
694
                }
737
                }
695
738
696
                if (isServiced(cn.getName()))
739
                if (isServiced(cn.getName()))
697
                    continue;
740
                    continue;
698
                
741
                
699
                String file = files[i];
742
                deployTasks++;
743
                deployExecutor.execute(new Runnable() {
744
745
                    @Override
746
                    public void run() {
747
                        try {
748
                            deployWAR(cn, dir, file);
749
                        } finally {
750
                            deployedLatch.countDown();
751
                        }
752
                    }
753
754
                });
700
                
755
                
701
                deployWAR(cn, dir, file);
702
            }
756
            }
703
        }
757
        }
758
759
        for (int i=deployTasks; i<files.length; i++) {
760
            deployedLatch.countDown();
761
        }
762
        try {
763
            deployedLatch.await();
764
        } catch (InterruptedException e) {
765
            log.error(sm.getString("hostConfig.awaitDeployIE"), e);
766
        }
704
    }
767
    }
705
768
706
769
Lines 940-961 public class HostConfig Link Here
940
        if (files == null)
1003
        if (files == null)
941
            return;
1004
            return;
942
        
1005
        
943
        for (int i = 0; i < files.length; i++) {
1006
        final CountDownLatch deployedLatch = new CountDownLatch(files.length);
944
1007
        int deployTasks = 0;
945
            if (files[i].equalsIgnoreCase("META-INF"))
1008
        
1009
        for (final String file: files) {
1010
            if (file.equalsIgnoreCase("META-INF"))
946
                continue;
1011
                continue;
947
            if (files[i].equalsIgnoreCase("WEB-INF"))
1012
            if (file.equalsIgnoreCase("WEB-INF"))
948
                continue;
1013
                continue;
949
            File dir = new File(appBase, files[i]);
1014
            final File dir = new File(appBase, file);
950
            if (dir.isDirectory()) {
1015
            if (dir.isDirectory()) {
951
                ContextName cn = new ContextName(files[i]);
1016
                final ContextName cn = new ContextName(file);
952
1017
953
                if (isServiced(cn.getName()))
1018
                if (isServiced(cn.getName()))
954
                    continue;
1019
                    continue;
1020
             
1021
                deployTasks++;
1022
                deployExecutor.execute(new Runnable() {
955
1023
956
                deployDirectory(cn, dir, files[i]);
1024
                    @Override
1025
                    public void run() {
1026
                        try {
1027
                            deployDirectory(cn, dir, file);
1028
                        } finally {
1029
                            deployedLatch.countDown();
1030
                        }
1031
                    }
1032
                    
1033
                });
957
            }
1034
            }
958
        }
1035
        }
1036
1037
        for (int i=deployTasks; i<files.length; i++) {
1038
            deployedLatch.countDown();
1039
        }
1040
        try {
1041
            deployedLatch.await();
1042
        } catch (InterruptedException e) {
1043
            log.error(sm.getString("hostConfig.awaitDeployIE"), e);
1044
        }
959
    }
1045
    }
960
1046
961
    
1047
    
Lines 1303-1308 public class HostConfig Link Here
1303
            host.setAutoDeploy(false);
1389
            host.setAutoDeploy(false);
1304
        }
1390
        }
1305
1391
1392
        initDeployExecutor();
1393
        
1306
        if (host.getDeployOnStartup())
1394
        if (host.getDeployOnStartup())
1307
            deployApps();
1395
            deployApps();
1308
        
1396
        
Lines 1310-1315 public class HostConfig Link Here
1310
1398
1311
1399
1312
    /**
1400
    /**
1401
     * Initialize executor for deployment.
1402
     */
1403
    private void initDeployExecutor() {
1404
        if (deployExecutor == null) {
1405
            int parallelCount = 0;
1406
            if (host.getStartupConcurrency() > 0) {
1407
                log.info(sm.getString("hostConfig.parallelDeploymentCount",
1408
                        host.getStartupConcurrency()));
1409
                parallelCount = host.getStartupConcurrency();
1410
            }
1411
            if (parallelCount == 0 && System.getProperty("hostConfig.parallelDeployment") != null) {
1412
                int parallelCountProperty = Integer.parseInt(System
1413
                        .getProperty("hostConfig.parallelDeployment"));
1414
                if (parallelCountProperty > 0) {
1415
                    log.info(sm.getString(
1416
                            "hostConfig.parallelDeploymentCount",
1417
                            parallelCountProperty));
1418
                    parallelCount = parallelCountProperty;
1419
                } else {
1420
                    log.info(sm
1421
                            .getString(
1422
                                    "hostConfig.invalidParallelDeploymentCount",
1423
                                    System.getProperty("hostConfig.parallelDeployment")));
1424
                }
1425
            }
1426
            if (parallelCount == 1) {
1427
                deployExecutor = new SameThreadExecutor();
1428
            } else {
1429
                if (parallelCount == 0) {
1430
                    parallelCount = Runtime.getRuntime().availableProcessors();
1431
                    log.info(sm.getString(
1432
                            "hostConfig.parallelDeploymentCountFromRuntime",
1433
                            parallelCount));
1434
                }
1435
                deployExecutor = Executors.newFixedThreadPool(parallelCount);
1436
            }
1437
        }
1438
    }
1439
    
1440
1441
    private static class SameThreadExecutor implements ExecutorService {
1442
1443
        private volatile boolean isShutdown = false;
1444
        
1445
        @Override
1446
        public void execute(Runnable command) {
1447
            if (!isShutdown && command != null)
1448
                command.run();
1449
        }
1450
1451
        @Override
1452
        public void shutdown() {
1453
        }
1454
1455
        @Override
1456
        public List<Runnable> shutdownNow() {
1457
            return Collections.emptyList();
1458
            }
1459
1460
        @Override
1461
        public boolean isShutdown() {
1462
            return isShutdown;
1463
        }
1464
1465
        @Override
1466
        public boolean isTerminated() {
1467
            return isShutdown;
1468
        }
1469
1470
        @Override
1471
        public boolean awaitTermination(long timeout, TimeUnit unit)
1472
                throws InterruptedException {
1473
            isShutdown = true;
1474
            return true;
1475
        }
1476
1477
        @Override
1478
        public <T> Future<T> submit(Callable<T> task) {
1479
            throw new RuntimeException("not implemented");
1480
        }
1481
1482
        @Override
1483
        public <T> Future<T> submit(Runnable task, T result) {
1484
            throw new RuntimeException("not implemented");
1485
        }
1486
1487
        @Override
1488
        public Future<?> submit(Runnable task) {
1489
            throw new RuntimeException("not implemented");
1490
        }
1491
1492
        @Override
1493
        public <T> List<Future<T>> invokeAll(
1494
                Collection<? extends Callable<T>> tasks)
1495
                throws InterruptedException {
1496
            throw new RuntimeException("not implemented");
1497
        }
1498
1499
        @Override
1500
        public <T> List<Future<T>> invokeAll(
1501
                Collection<? extends Callable<T>> tasks, long timeout,
1502
                TimeUnit unit) throws InterruptedException {
1503
            throw new RuntimeException("not implemented");
1504
        }
1505
1506
        @Override
1507
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
1508
                throws InterruptedException, ExecutionException {
1509
            throw new RuntimeException("not implemented");
1510
        }
1511
1512
        @Override
1513
        public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
1514
                long timeout, TimeUnit unit) throws InterruptedException,
1515
                ExecutionException, TimeoutException {
1516
            throw new RuntimeException("not implemented");
1517
        }
1518
1519
    }
1520
1521
    /**
1313
     * Process a "stop" event for this Host.
1522
     * Process a "stop" event for this Host.
1314
     */
1523
     */
1315
    public void stop() {
1524
    public void stop() {
Lines 1326-1331 public class HostConfig Link Here
1326
        }
1535
        }
1327
        oname = null;
1536
        oname = null;
1328
        configBase = null;
1537
        configBase = null;
1538
        
1539
        if (deployExecutor != null) {
1540
            deployExecutor.shutdown();
1541
            try {
1542
                if (!deployExecutor.awaitTermination(1, TimeUnit.MINUTES)) 
1543
                    log.warn(sm.getString("hostConfig.awaitDeployExecutorShutdownFailed"));
1544
            } catch (InterruptedException e) {
1545
                log.error(
1546
                        sm.getString("hostConfig.awaitDeployExecutorShutdownIE"),
1547
                        e);
1548
            }
1549
        }
1329
1550
1330
    }
1551
    }
1331
1552
Lines 1343-1348 public class HostConfig Link Here
1343
                if (!isServiced(apps[i].name))
1564
                if (!isServiced(apps[i].name))
1344
                    checkResources(apps[i]);
1565
                    checkResources(apps[i]);
1345
            }
1566
            }
1567
            
1568
            initDeployExecutor();
1346
            // Hotdeploy applications
1569
            // Hotdeploy applications
1347
            deployApps();
1570
            deployApps();
1348
        }
1571
        }
(-)a/java/org/apache/catalina/startup/LocalStrings.properties (+6 lines)
Lines 73-78 expandWar.copy=Error copying {0} to {1} Link Here
73
expandWar.deleteFailed=[{0}] could not be completely deleted. The presence of the remaining files may cause problems
73
expandWar.deleteFailed=[{0}] could not be completely deleted. The presence of the remaining files may cause problems
74
expandWar.illegalPath=The archive [{0}] is malformed and will be ignored: an entry contains an illegal path [{1}] which was not expanded to [{2}] since that is outside of the defined docBase [{3}]
74
expandWar.illegalPath=The archive [{0}] is malformed and will be ignored: an entry contains an illegal path [{1}] which was not expanded to [{2}] since that is outside of the defined docBase [{3}]
75
hostConfig.appBase=Application base [{1}] for host [{0}] does not exist or is not a directory. deployOnStartUp and autoDeploy have been set to false to prevent deployment errors. Other errors may still occur.
75
hostConfig.appBase=Application base [{1}] for host [{0}] does not exist or is not a directory. deployOnStartUp and autoDeploy have been set to false to prevent deployment errors. Other errors may still occur.
76
hostConfig.awaitDeployIE=Interrupted while waiting for contexts to be deployed
77
hostConfig.awaitDeployExecutorShutdownFailed=Error while waiting for deployment executor to shutdown
78
hostConfig.awaitDeployExecutorShutdownIE=Interrupted while waiting for deployment executor to shutdown
76
hostConfig.canonicalizing=Error delete redeploy resources from context [{0}]
79
hostConfig.canonicalizing=Error delete redeploy resources from context [{0}]
77
hostConfig.cce=Lifecycle event data object {0} is not a Host
80
hostConfig.cce=Lifecycle event data object {0} is not a Host
78
hostConfig.context.remove=Error while removing context [{0}]
81
hostConfig.context.remove=Error while removing context [{0}]
Lines 93-100 hostConfig.expand.error=Exception while expanding web application archive {0} Link Here
93
hostConfig.expanding=Expanding discovered web application archives
96
hostConfig.expanding=Expanding discovered web application archives
94
hostConfig.ignorePath=Ignoring path [{0}] in appBase for automatic deployment
97
hostConfig.ignorePath=Ignoring path [{0}] in appBase for automatic deployment
95
hostConfig.illegalWarName=The war name [{0}] is invalid. The archive will be ignored.
98
hostConfig.illegalWarName=The war name [{0}] is invalid. The archive will be ignored.
99
hostConfig.invalidParallelDeploymentCount=Invalid number of threads: [{0}]
96
hostConfig.jmx.register=Register context [{0}] failed
100
hostConfig.jmx.register=Register context [{0}] failed
97
hostConfig.jmx.unregister=Unregister context [{0}] failed
101
hostConfig.jmx.unregister=Unregister context [{0}] failed
102
hostConfig.parallelDeploymentCount=Start fixed executor for deployment with [{0}] parallel threads
103
hostConfig.parallelDeploymentCountFromRuntime=Start fixed executor for deployment with [{0}] parallel threads as given by Runtime
98
hostConfig.reload=Reloading context [{0}]
104
hostConfig.reload=Reloading context [{0}]
99
hostConfig.removeXML=Context [{0}] is undeployed
105
hostConfig.removeXML=Context [{0}] is undeployed
100
hostConfig.removeDIR=Directory {0} is undeployed
106
hostConfig.removeDIR=Directory {0} is undeployed
(-)a/java/org/apache/tomcat/util/digester/Digester.java (-1 / +7 lines)
Lines 277-283 public class Digester extends DefaultHandler { Link Here
277
    /**
277
    /**
278
     * The XMLReader used to parse digester rules.
278
     * The XMLReader used to parse digester rules.
279
     */
279
     */
280
    protected XMLReader reader = null;
280
    protected volatile XMLReader reader = null;
281
281
282
282
283
    /**
283
    /**
Lines 884-889 public class Digester extends DefaultHandler { Link Here
884
     */
884
     */
885
    public XMLReader getXMLReader() throws SAXException {
885
    public XMLReader getXMLReader() throws SAXException {
886
        if (reader == null){
886
        if (reader == null){
887
            synchronized (this) {
888
                if (reader == null) {
889
                    XMLReader tmpReader = getParser().getXMLReader();
890
                    reader = tmpReader;
891
                }
892
			}
887
            reader = getParser().getXMLReader();
893
            reader = getParser().getXMLReader();
888
        }        
894
        }        
889
                               
895
                               

Return to bug 46264