43
43
import java.util.Map;
44
44
import java.util.Properties;
45
45
import java.util.Set;
46
import java.util.jar.JarEntry;
47
import java.util.jar.JarInputStream;
49
47
import javax.servlet.ServletContainerInitializer;
50
48
import javax.servlet.ServletContext;
92
90
import org.apache.tomcat.util.digester.Digester;
93
91
import org.apache.tomcat.util.digester.RuleSet;
94
92
import org.apache.tomcat.util.res.StringManager;
93
import org.apache.tomcat.util.scan.Jar;
94
import org.apache.tomcat.util.scan.JarFactory;
95
95
import org.xml.sax.InputSource;
96
96
import org.xml.sax.SAXParseException;
102
102
* @author Craig R. McClanahan
103
103
* @author Jean-Francois Arcand
104
* @version $Id: ContextConfig.java 1095449 2011-04-20 16:19:59Z markt $
104
* @version $Id: ContextConfig.java 1133446 2011-06-08 15:52:26Z markt $
107
107
public class ContextConfig
1187
1187
protected void webConfig() {
1188
1188
WebXml webXml = createWebXml();
1189
/* Anything and everything can override the global and host defaults.
1190
* This is implemented in two parts
1191
* - Handle as a web fragment that gets added after everything else so
1192
* everything else takes priority
1193
* - Mark Servlets as overridable so SCI configuration can replace
1194
* configuration from the defaults
1196
WebXml webXmlDefaultFragment = createWebXml();
1197
webXmlDefaultFragment.setOverridable(true);
1198
// Set to distributable else every app will be prevented from being
1199
// distributable when the default fragment is merged with the main
1201
webXmlDefaultFragment.setDistributable(true);
1202
// When merging, the default welcome files are only used if the app has
1203
// not defined any welcomes files.
1204
webXmlDefaultFragment.setAlwaysAddWelcomeFiles(false);
1190
1206
// Parse global web.xml if present
1191
1207
InputSource globalWebXml = getGlobalWebXmlSource();
1193
1209
// This is unusual enough to log
1194
1210
log.info(sm.getString("contextConfig.defaultMissing"));
1196
parseWebXml(globalWebXml, webXml, false);
1212
parseWebXml(globalWebXml, webXmlDefaultFragment, false);
1199
1215
// Parse host level web.xml if present
1200
1216
// Additive apart from welcome pages
1201
webXml.setReplaceWelcomeFiles(true);
1217
webXmlDefaultFragment.setReplaceWelcomeFiles(true);
1202
1218
InputSource hostWebXml = getHostWebXmlSource();
1203
parseWebXml(hostWebXml, webXml, false);
1219
parseWebXml(hostWebXml, webXmlDefaultFragment, false);
1221
Set<WebXml> defaults = new HashSet<WebXml>();
1222
defaults.add(webXmlDefaultFragment);
1205
1224
// Parse context level web.xml
1206
webXml.setReplaceWelcomeFiles(true);
1207
1225
InputSource contextWebXml = getContextWebXmlSource();
1208
1226
parseWebXml(contextWebXml, webXml, false);
1210
// Assuming 0 is safe for what is required in this case
1211
double webXmlVersion = 0;
1212
if (webXml.getVersion() != null) {
1213
webXmlVersion = Double.parseDouble(webXml.getVersion());
1216
if (webXmlVersion >= 3) {
1228
if (webXml.getMajorVersion() >= 3) {
1217
1229
// Ordering is important here
1219
1231
// Step 1. Identify all the JARs packaged with the application
1260
1272
ok = webXml.merge(orderedFragments);
1263
// Step 6.5 Convert explicitly mentioned jsps to servlets
1275
// Step 7. Apply global defaults
1276
// Have to merge defaults before JSP conversion since defaults
1277
// provide JSP servlet definition.
1278
webXml.merge(defaults);
1280
// Step 8. Convert explicitly mentioned jsps to servlets
1265
1282
convertJsps(webXml);
1268
// Step 7. Apply merged web.xml to Context
1285
// Step 9. Apply merged web.xml to Context
1270
1287
webXml.configureContext(context);
1272
// Step 7a. Make the merged web.xml available to other
1289
// Step 9a. Make the merged web.xml available to other
1273
1290
// components, specifically Jasper, to save those components
1274
1291
// from having to re-generate it.
1275
1292
// TODO Use a ServletContainerInitializer for Jasper
1302
webXml.merge(defaults);
1285
1303
webXml.configureContext(context);
1288
1306
// Always need to look for static resources
1289
// Step 8. Look for static resources packaged in JARs
1307
// Step 10. Look for static resources packaged in JARs
1291
1309
// Spec does not define an order.
1292
1310
// Use ordered JARs followed by remaining JARs
1309
1327
// Only look for ServletContainerInitializer if metadata is not
1311
1329
if (!webXml.isMetadataComplete()) {
1312
// Step 9. Apply the ServletContainerInitializer config to the
1330
// Step 11. Apply the ServletContainerInitializer config to the
1315
1333
for (Map.Entry<ServletContainerInitializer,
1376
1395
for (WebXml fragment : fragments) {
1377
1396
URL url = fragment.getURL();
1378
JarInputStream jarInputStream = null;
1379
1398
InputStream is = null;
1380
1399
ServletContainerInitializer sci = null;
1382
1401
if ("jar".equals(url.getProtocol())) {
1383
JarURLConnection jarConn =
1384
(JarURLConnection) url.openConnection();
1385
URL resourceURL = jarConn.getJarFileURL();
1386
URLConnection resourceConn = resourceURL.openConnection();
1387
resourceConn.setUseCaches(false);
1390
new JarInputStream(resourceConn.getInputStream());
1391
JarEntry entry = jarInputStream.getNextJarEntry();
1392
while (entry != null) {
1393
if (SCI_LOCATION.equals(entry.getName())) {
1396
entry = jarInputStream.getNextJarEntry();
1398
if (entry != null) {
1399
is = jarInputStream;
1402
jar = JarFactory.newInstance(url);
1403
is = jar.getInputStream(SCI_LOCATION);
1401
1404
} else if ("file".equals(url.getProtocol())) {
1402
1405
String path = url.getPath();
1403
1406
File file = new File(path, SCI_LOCATION);
1514
1513
protected void processResourceJARs(Set<WebXml> fragments) {
1515
1514
for (WebXml fragment : fragments) {
1516
1515
URL url = fragment.getURL();
1517
JarInputStream jarInputStream = null;
1519
1518
// Note: Ignore file URLs for now since only jar URLs will be accepted
1520
1519
if ("jar".equals(url.getProtocol())) {
1521
JarURLConnection jarConn =
1522
(JarURLConnection) url.openConnection();
1523
URL resourceURL = jarConn.getJarFileURL();
1524
URLConnection resourceConn = resourceURL.openConnection();
1525
resourceConn.setUseCaches(false);
1527
new JarInputStream(resourceConn.getInputStream());
1528
JarEntry entry = jarInputStream.getNextJarEntry();
1529
while (entry != null) {
1530
if ("META-INF/resources/".equals(entry.getName())) {
1533
entry = jarInputStream.getNextJarEntry();
1535
if (entry != null) {
1520
jar = JarFactory.newInstance(url);
1521
if (jar.entryExists("META-INF/resources/")) {
1536
1522
context.addResourceJarUrl(url);
1694
1676
// thread safe. Whilst there should only be one thread at a time
1695
1677
// processing a config, play safe and sync.
1696
1678
Digester digester;
1697
1680
if (fragment) {
1698
1681
digester = webFragmentDigester;
1682
ruleSet = webFragmentRuleSet;
1700
1684
digester = webDigester;
1685
ruleSet = webRuleSet;
1703
synchronized(digester) {
1688
// Sync on the ruleSet since the same ruleSet is shared across all four
1690
synchronized(ruleSet) {
1705
1692
digester.push(dest);
1706
1693
digester.setErrorHandler(handler);
1802
1785
protected void processAnnotationsJar(URL url, WebXml fragment) {
1803
JarInputStream jarInputStream = null;
1806
URLConnection urlConn = url.openConnection();
1807
JarURLConnection jarConn;
1808
if (!(urlConn instanceof JarURLConnection)) {
1809
// This should never happen
1810
sm.getString("contextConfig.jarUrl", url);
1791
jar = JarFactory.newInstance(url);
1814
jarConn = (JarURLConnection) urlConn;
1815
jarConn.setUseCaches(false);
1816
URL resourceURL = jarConn.getJarFileURL();
1817
URLConnection resourceConn = resourceURL.openConnection();
1819
jarInputStream = new JarInputStream(resourceConn.getInputStream());
1821
JarEntry entry = jarInputStream.getNextJarEntry();
1822
while (entry != null) {
1823
String entryName = entry.getName();
1794
String entryName = jar.getEntryName();
1795
while (entryName != null) {
1824
1796
if (entryName.endsWith(".class")) {
1826
processAnnotationsStream(jarInputStream, fragment);
1799
is = jar.getEntryInputStream();
1800
processAnnotationsStream(is, fragment);
1827
1801
} catch (IOException e) {
1828
1802
log.error(sm.getString("contextConfig.inputStreamJar",
1829
1803
entryName, url),e);
1808
} catch (IOException ioe) {
1832
entry = jarInputStream.getNextJarEntry();
1815
entryName = jar.getEntryName();
1834
1817
} catch (IOException e) {
1835
1818
log.error(sm.getString("contextConfig.jarFile", url), e);
1837
if (jarInputStream != null) {
1839
jarInputStream.close();
1840
} catch (Throwable t) {
1841
ExceptionUtils.handleThrowable(t);
2318
2297
public void scan(JarURLConnection jarConn) throws IOException {
2320
// JarURLConnection#getJarFile() creates temporary copies of the JAR
2321
// if the underlying resource is not a file URL. That can be slow so
2322
// the InputStream for the resource is used
2299
URL url = jarConn.getURL();
2323
2300
URL resourceURL = jarConn.getJarFileURL();
2325
JarInputStream jarInputStream = null;
2302
InputStream is = null;
2326
2303
WebXml fragment = new WebXml();
2329
URLConnection resourceConn = resourceURL.openConnection();
2330
resourceConn.setUseCaches(false);
2332
new JarInputStream(resourceConn.getInputStream());
2333
JarEntry entry = jarInputStream.getNextJarEntry();
2334
while (entry != null) {
2335
if (FRAGMENT_LOCATION.equals(entry.getName())) {
2338
entry = jarInputStream.getNextJarEntry();
2306
jar = JarFactory.newInstance(url);
2307
is = jar.getInputStream(FRAGMENT_LOCATION);
2341
if (entry == null) {
2342
2310
// If there is no web.xml, normal JAR no impact on
2343
2311
// distributable
2344
2312
fragment.setDistributable(true);
2346
2314
InputSource source = new InputSource(
2347
2315
resourceURL.toString() + "!/" + FRAGMENT_LOCATION);
2348
source.setByteStream(jarInputStream);
2316
source.setByteStream(is);
2349
2317
parseWebXml(source, fragment, true);
2352
if (jarInputStream != null) {
2354
jarInputStream.close();
2355
} catch (Throwable t) {
2356
ExceptionUtils.handleThrowable(t);
2323
} catch (IOException ioe) {
2359
fragment.setURL(jarConn.getURL());
2330
fragment.setURL(url);
2360
2331
if (fragment.getName() == null) {
2361
2332
fragment.setName(fragment.getURL().toString());