aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVioleta Georgieva2010-07-08 11:21:08 (EDT)
committerGlyn Normington2010-07-08 11:22:58 (EDT)
commite9142ece90ac9c8c43ead7d0c32127ea42148302 (patch)
tree22ad0fb6a120e6fd09b1b40049bc5743ecce8d74
parent4feac292ffbb339d33f585f7b86a49e1997e0d8b (diff)
downloadorg.eclipse.gemini.web.gemini-web-container-e9142ece90ac9c8c43ead7d0c32127ea42148302.zip
org.eclipse.gemini.web.gemini-web-container-e9142ece90ac9c8c43ead7d0c32127ea42148302.tar.gz
org.eclipse.gemini.web.gemini-web-container-e9142ece90ac9c8c43ead7d0c32127ea42148302.tar.bz2
bug 312752: support for configuring Context elements for all web apps
Author: Violeta Georgieva <milesg78@gmail.com>
-rw-r--r--org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java70
-rwxr-xr-xorg.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-cross-context.warbin0 -> 941 bytes
-rwxr-xr-xorg.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-resources.warbin0 -> 1278 bytes
-rw-r--r--org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/Tomcat.java185
-rw-r--r--org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocator.java38
-rwxr-xr-xorg.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocator.java177
-rw-r--r--org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocatorTests.java24
-rwxr-xr-xorg.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocatorTest.java193
-rwxr-xr-xorg.eclipse.gemini.web.tomcat/src/test/resources/META-INF/context.xml0
-rwxr-xr-xorg.eclipse.gemini.web.tomcat/src/test/resources/test.xml5
10 files changed, 545 insertions, 147 deletions
diff --git a/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java b/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
index e5d0c6e..2acfffd 100644
--- a/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
+++ b/org.eclipse.gemini.web.test/src/test/java/org/eclipse/gemini/web/test/tomcat/TomcatServletContainerTests.java
@@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -47,6 +49,7 @@ import org.eclipse.gemini.web.core.spi.ServletContainer;
import org.eclipse.gemini.web.core.spi.WebApplicationHandle;
import org.eclipse.virgo.test.framework.OsgiTestRunner;
import org.eclipse.virgo.test.framework.TestFrameworkUtils;
+import org.eclipse.virgo.util.io.IOUtils;
import org.eclipse.virgo.util.io.PathReference;
import org.eclipse.virgo.util.io.ZipUtils;
@@ -75,6 +78,12 @@ public class TomcatServletContainerTests {
private static final String LOCATION_WAR_WITH_TLD_IMPORT_SYSTEM_PACKAGES = LOCATION_PREFIX
+ "../org.eclipse.gemini.web.test/src/test/resources/war-with-tld-import-system-packages.war?Web-ContextPath=/war-with-tld-import-system-packages";
+ private static final String LOCATION_WAR_WITH_CONTEXT_XML_RESOURCES = LOCATION_PREFIX
+ + "../org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-resources.war?Web-ContextPath=/war-with-context-xml-resources";
+
+ private static final String LOCATION_WAR_WITH_CONTEXT_XML_CROSS_CONTEXT = LOCATION_PREFIX
+ + "../org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-cross-context.war?Web-ContextPath=/war-with-context-xml-cross-context";
+
private BundleContext bundleContext;
private ServletContainer container;
@@ -338,4 +347,65 @@ public class TomcatServletContainerTests {
this.container.stopWebApplication(handle);
}
}
+
+ @Test
+ public void testWarWithContextXml() throws Exception {
+ // Copy default context.xml
+ File defaultContextXml = new File("config/context.xml");
+ createFileWithContent(defaultContextXml, "<Context crossContext=\"true\"/>");
+
+ // Copy default context.xml.default
+ File defaultHostContextXml = new File("config/Catalina/localhost/context.xml.default");
+ String content = "<Context>"
+ + "<Resource name=\"mail/Session1\" auth=\"Container\" type=\"javax.mail.Session\" mail.smtp.host=\"localhost\"/>"
+ + "</Context>";
+ createFileWithContent(defaultHostContextXml, content);
+
+ File tomcatServerXml = new File("config/tomcat-server.xml");
+ createFileWithContent(tomcatServerXml, "");
+
+ String location1 = LOCATION_WAR_WITH_CONTEXT_XML_RESOURCES;
+ Bundle bundle1 = this.bundleContext.installBundle(location1);
+ bundle1.start();
+
+ String location2 = LOCATION_WAR_WITH_CONTEXT_XML_CROSS_CONTEXT;
+ Bundle bundle2 = this.bundleContext.installBundle(location2);
+ bundle2.start();
+
+ WebApplicationHandle handle1 = this.container.createWebApplication("/war-with-context-xml-resources", bundle1);
+ this.container.startWebApplication(handle1);
+
+ WebApplicationHandle handle2 = this.container.createWebApplication("/war-with-context-xml-cross-context",
+ bundle2);
+ this.container.startWebApplication(handle2);
+ try {
+ // tests JNDI resources
+ validateURL("http://localhost:8080/war-with-context-xml-resources/index.jsp");
+
+ // tests cross context functionality
+ validateURL("http://localhost:8080/war-with-context-xml-cross-context/index.jsp");
+ } finally {
+ this.container.stopWebApplication(handle1);
+ bundle1.uninstall();
+
+ this.container.stopWebApplication(handle2);
+ bundle2.uninstall();
+
+ defaultContextXml.delete();
+ defaultHostContextXml.delete();
+ tomcatServerXml.delete();
+ }
+ }
+
+ private void createFileWithContent(File file, String content) throws Exception {
+ file.getParentFile().mkdirs();
+ FileWriter fWriter = null;
+ try {
+ fWriter = new FileWriter(file);
+ fWriter.write(content);
+ fWriter.flush();
+ } finally {
+ IOUtils.closeQuietly(fWriter);
+ }
+ }
}
diff --git a/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-cross-context.war b/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-cross-context.war
new file mode 100755
index 0000000..26fecfc
--- /dev/null
+++ b/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-cross-context.war
Binary files differ
diff --git a/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-resources.war b/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-resources.war
new file mode 100755
index 0000000..102bc64
--- /dev/null
+++ b/org.eclipse.gemini.web.test/src/test/resources/war-with-context-xml-resources.war
Binary files differ
diff --git a/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/Tomcat.java b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/Tomcat.java
index db1828c..78709de 100644
--- a/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/Tomcat.java
+++ b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/Tomcat.java
@@ -17,13 +17,8 @@
package org.eclipse.gemini.web.tomcat.internal;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
@@ -45,7 +40,6 @@ import org.eclipse.gemini.web.core.spi.ServletContainerException;
import org.eclipse.gemini.web.tomcat.internal.loading.ChainedClassLoader;
import org.eclipse.gemini.web.tomcat.internal.support.BundleFileResolverFactory;
import org.eclipse.gemini.web.tomcat.internal.support.PackageAdminBundleDependencyDeterminer;
-import org.eclipse.virgo.util.io.IOUtils;
import org.osgi.framework.BundleContext;
import org.osgi.service.packageadmin.PackageAdmin;
import org.slf4j.Logger;
@@ -58,40 +52,22 @@ final class Tomcat extends Embedded {
private static final String ROOT_CONTEXT_PATH = "";
private static final String ROOT_PATH = "/";
-
- private static final String ROOT_CONTEXT_FILE = "ROOT";
-
- private static final String CONTEXT_XML = "META-INF/context.xml";
-
- private static final String CONTEXT_PROPERTY = "Context";
-
- private static final String XML_EXTENSION = ".xml";
-
- private static final char SLASH_SEPARATOR = '/';
-
- private static final char HASH_SEPARATOR = '#';
-
- private static final String DEFAULT_CONFIG_DIRECTORY = "config";
private final static Logger LOGGER = LoggerFactory.getLogger(Tomcat.class);
private final ExtendCatalina catalina = new ExtendCatalina();
private final JarScanner jarScanner;
-
- private Digester digester;
private BundleContext bundleContext;
Tomcat(BundleContext context, PackageAdmin packageAdmin) {
- this.bundleContext = context;
+ this.bundleContext = context;
JarScanner bundleDependenciesJarScanner = new BundleDependenciesJarScanner(new PackageAdminBundleDependencyDeterminer(context, packageAdmin),
BundleFileResolverFactory.createBundleFileResolver());
JarScanner defaultJarScanner = new DefaultJarScanner();
this.jarScanner = new ChainingJarScanner(bundleDependenciesJarScanner, defaultJarScanner);
-
- digester = createDigester();
}
public void start() throws LifecycleException {
@@ -165,15 +141,34 @@ final class Tomcat extends Embedded {
}
StandardContext context = new ExtendedStandardContext();
- readContextXml(path, docBase, context);
+
+ ExtendedContextConfig config = new ExtendedContextConfig();
+
+ // Allocate the tomcat's configuration directory
+ File configDir = TomcatConfigLocator.resolveConfigDir(bundleContext);
+ config.setConfigBase(configDir);
+
+ // If default context.xml is existing, set it to the ContextConfig
+ String defaultContextXml = WebappConfigLocator.resolveDefaultContextXml(configDir);
+ if (defaultContextXml != null) {
+ config.setDefaultContextXml(defaultContextXml);
+ }
+
+ // Allocate the web application's configuration directory
+ File configLocation = WebappConfigLocator.resolveWebappConfigDir(configDir, findHost());
+
+ // If web application's context.xml is existing, set it to the
+ // StandardContext
+ File contextXml = WebappConfigLocator.resolveWebappContextXml(path, docBase, configLocation);
+ if (contextXml != null) {
+ context.setConfigFile(contextXml.getAbsolutePath());
+ }
context.setDocBase(docBase);
context.setPath(path.equals(ROOT_PATH) ? ROOT_CONTEXT_PATH : path);
context.setJarScanner(this.jarScanner);
- ContextConfig config = new ExtendedContextConfig();
-
config.setCustomAuthenticators(this.authenticators);
((Lifecycle) context).addLifecycleListener(config);
@@ -238,133 +233,29 @@ final class Tomcat extends Embedded {
*
*/
private static class ExtendedContextConfig extends ContextConfig {
- }
-
- private Digester createDigester() {
- Digester digester = new Digester();
- ClassLoader[] loaders = new ClassLoader[] { Catalina.class.getClassLoader(), Tomcat.class.getClassLoader() };
- digester.setClassLoader(ChainedClassLoader.create(loaders));
- digester.setValidating(false);
- digester.addSetProperties(CONTEXT_PROPERTY);
- return (digester);
- }
+ private File configDir;
- private void readContextXml(String path, String docBase, StandardContext context) {
- // Multi-level context paths may be defined using #, e.g. foo#bar.xml
- // for a context path of /foo/bar.
- if (path.equals(ROOT_PATH)) {
- path = ROOT_CONTEXT_FILE;
- } else if (SLASH_SEPARATOR == path.charAt(0)) {
- path = path.substring(1);
- }
- path = path.replace(SLASH_SEPARATOR, HASH_SEPARATOR);
-
- // Initialize config directory location
- File configLocation = new File(resolveConfigDir());
- Host host = findHost();
- Container parent = host.getParent();
- if ((parent != null) && (parent instanceof Engine)) {
- configLocation = new File(configLocation, parent.getName());
- }
- configLocation = new File(configLocation, host.getName());
-
- // Try to find the context.xml in the Tomcat's configuration directory
- File contextXml = new File(configLocation, path + XML_EXTENSION);
- if (contextXml.exists()) {
- configureWebContext(contextXml, context);
- return;
- }
-
- // Try to find the context.xml in docBase
- File docBaseFile = new File(docBase);
- if (docBaseFile.isDirectory()) {
- contextXml = new File(docBaseFile, CONTEXT_XML);
- if (contextXml.exists()) {
- File destination = new File(configLocation, path + XML_EXTENSION);
- try {
- copyFile(new FileInputStream(contextXml), destination);
- } catch (IOException e) {
- throw new ServletContainerException("Cannot copy " + contextXml.getAbsolutePath() + " to "
- + destination.getAbsolutePath(), e);
- }
- configureWebContext(destination, context);
- }
- } else {
- JarFile jar;
- try {
- jar = new JarFile(docBaseFile);
- } catch (IOException e) {
- throw new ServletContainerException("Cannot open for reading " + docBaseFile.getAbsolutePath(), e);
- }
- ZipEntry contextXmlEntry = jar.getEntry(CONTEXT_XML);
- if (contextXmlEntry != null) {
- File destination = new File(configLocation, path + XML_EXTENSION);
- try {
- copyFile(jar.getInputStream(contextXmlEntry), destination);
- } catch (IOException e) {
- throw new ServletContainerException("Cannot copy " + contextXml.getAbsolutePath() + " to "
- + destination.getAbsolutePath(), e);
- }
- configureWebContext(destination, context);
+ /**
+ * If there is not configuration directory, return custom configuration
+ * directory. It is used to resolve the context.xml.default
+ */
+ @Override
+ protected File getConfigBase() {
+ File configBase = super.getConfigBase();
+ if (configBase != null) {
+ return configBase;
}
- }
- }
-
- private String resolveConfigDir() {
- File configFile = null;
- // Search for the property 'org.eclipse.gemini.web.tomcat.config.path'
- String path = bundleContext.getProperty(TomcatConfigLocator.CONFIG_PATH_FRAMEWORK_PROPERTY);
- if (path != null) {
- configFile = new File(path);
- if (configFile.exists()) {
- return configFile.getParent();
+ if (configDir != null) {
+ return configDir;
}
- }
- // Search for the 'config' directory
- configFile = new File(TomcatConfigLocator.DEFAULT_CONFIG_FILE_PATH);
- if (configFile.exists()) {
- return configFile.getParent();
- } else {
- return DEFAULT_CONFIG_DIRECTORY;
+ return null;
}
- }
- private void configureWebContext(File contextXml, StandardContext context) {
- synchronized (digester) {
- try {
- digester.push(context);
- try {
- digester.parse(contextXml);
- context.setConfigFile(contextXml.getAbsolutePath());
- } catch (IOException e) {
- throw new ServletContainerException("Cannot read " + contextXml.getAbsolutePath()
- + " for web application.", e);
- } catch (SAXException e) {
- throw new ServletContainerException("Cannot parse " + contextXml.getAbsolutePath()
- + " for web application.", e);
- }
- } finally {
- digester.reset();
- }
+ protected void setConfigBase(File configDir) {
+ this.configDir = configDir;
}
}
- private void copyFile(InputStream source, File destination) throws IOException {
- destination.getParentFile().mkdirs();
-
- OutputStream outputStream = null;
- try {
- outputStream = new FileOutputStream(destination);
- byte[] buffer = new byte[1024];
- int read;
- while ((read = source.read(buffer)) > 0) {
- outputStream.write(buffer, 0, read);
- }
- } finally {
- IOUtils.closeQuietly(source);
- IOUtils.closeQuietly(outputStream);
- }
- }
}
diff --git a/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocator.java b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocator.java
index 837a099..160a2a3 100644
--- a/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocator.java
+++ b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocator.java
@@ -68,6 +68,44 @@ final class TomcatConfigLocator {
return is;
}
+ /**
+ * Returns the directory where the Tomcat configuration files resides.
+ *
+ * The location algorithm is as follows:
+ * <ol>
+ * <li>Check for <code>org.eclipse.gemini.web.tomcat.config.path</code>
+ * framework property, use if found</li>
+ * <li>Check for <code>config/tomcat-server.xml</code> in the current
+ * working directory, use if found</li>
+ * <li>If the previous checks do not return a result, return
+ * <code>null</code></li>
+ * </ol>
+ *
+ * @param context
+ * the bundle context
+ * @return the directory where the Tomcat configuration files resides.
+ */
+ public static File resolveConfigDir(BundleContext context) {
+ File configFile = null;
+
+ // Search for the property 'org.eclipse.gemini.web.tomcat.config.path'
+ String path = context.getProperty(TomcatConfigLocator.CONFIG_PATH_FRAMEWORK_PROPERTY);
+ if (path != null) {
+ configFile = new File(path);
+ if (configFile.exists()) {
+ return configFile.getParentFile();
+ }
+ }
+
+ // Search for the 'config' directory
+ configFile = new File(TomcatConfigLocator.DEFAULT_CONFIG_FILE_PATH);
+ if (configFile.exists()) {
+ return configFile.getParentFile();
+ }
+
+ return null;
+ }
+
private static InputStream lookupConfigInFileSystem(BundleContext context) {
InputStream result = null;
diff --git a/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocator.java b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocator.java
new file mode 100755
index 0000000..79cf128
--- /dev/null
+++ b/org.eclipse.gemini.web.tomcat/src/main/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocator.java
@@ -0,0 +1,177 @@
+package org.eclipse.gemini.web.tomcat.internal;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.eclipse.gemini.web.core.spi.ServletContainerException;
+import org.eclipse.virgo.util.io.IOUtils;
+
+public class WebappConfigLocator {
+
+ static final String DEFAULT_CONFIG_DIRECTORY = "config";
+
+ private static final String DEFAULT_CONTEXT_XML = "context.xml";
+
+ private static final String CONTEXT_XML = "META-INF/context.xml";
+
+ private static final String XML_EXTENSION = ".xml";
+
+ private static final String ROOT_PATH = "/";
+
+ private static final String ROOT_CONTEXT_FILE = "ROOT";
+
+ private static final char SLASH_SEPARATOR = '/';
+
+ private static final char HASH_SEPARATOR = '#';
+
+ /**
+ * Resolves the default context.xml and returns a relative path to it, if it
+ * exists in the main Tomcat's configuration directory, otherwise returns
+ * <code>null</code>. The method returns <code>null</code> also in case main
+ * Tomcat's configuration directory does not exists.
+ *
+ * @param configLocation
+ * the main Tomcat's configuration directory
+ * @return a relative path to default context.xml file, if it exists in the
+ * main Tomcat's configuration directory, otherwise returns
+ * <code>null</code>.
+ */
+ public static String resolveDefaultContextXml(File configLocation) {
+ if (configLocation == null) {
+ return null;
+ }
+
+ File defaultContextXml = new File(configLocation, DEFAULT_CONTEXT_XML);
+ if (defaultContextXml.exists()) {
+ return getRelativePath(defaultContextXml);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Resolves the web application's specific context.xml The algorithm is the
+ * following:
+ * <ol>
+ * <li>The composite context path i.e. /foo/bar are formated. The "/" are
+ * replaced with "#" i.e. foo#bar</li>
+ * <li>Check for <code><formated-web-app-context-path>.xml</code> file in
+ * the main Tomcat Host's configuration directory, use if found</li>
+ * <li>If <code>docBase</code> is directory check for
+ * <code>META-INF/context.xml</code> file, use if found</li>
+ * <li>If <code>docBase</code> is an archive check for
+ * <code>META-INF/context.xml</code> entry. If it exists, copy it to the
+ * main Tomcat Host's configuration directory and use it. The next time this
+ * copy will be used instead of the one in the archive.</li>
+ * <li>Return <code>null</code> in other cases.</li>
+ * </ol>
+ *
+ * @param path
+ * the context path
+ * @param docBase
+ * the root directory/file for the web application
+ * @param configLocation
+ * Host's configuration directory
+ * @return the context.xml if it is found following the algorithm above,
+ * otherwise <code>null</code>
+ */
+ public static File resolveWebappContextXml(String path, String docBase, File configLocation) {
+ path = formatContextPath(path);
+
+ // Try to find the context.xml in the Tomcat's configuration directory
+ File contextXml = new File(configLocation, path + XML_EXTENSION);
+ if (contextXml.exists()) {
+ return contextXml;
+ }
+
+ // Try to find the context.xml in docBase
+ File docBaseFile = new File(docBase);
+ if (docBaseFile.isDirectory()) {
+ contextXml = new File(docBaseFile, CONTEXT_XML);
+ if (contextXml.exists()) {
+ return contextXml;
+ }
+ } else {
+ JarFile jar;
+ try {
+ jar = new JarFile(docBaseFile);
+ } catch (IOException e) {
+ throw new ServletContainerException("Cannot open for reading " + docBaseFile.getAbsolutePath(), e);
+ }
+ ZipEntry contextXmlEntry = jar.getEntry(CONTEXT_XML);
+ if (contextXmlEntry != null) {
+ File destination = new File(configLocation, path + XML_EXTENSION);
+ try {
+ copyFile(jar.getInputStream(contextXmlEntry), destination);
+ } catch (IOException e) {
+ throw new ServletContainerException("Cannot copy " + contextXml.getAbsolutePath() + " to "
+ + destination.getAbsolutePath(), e);
+ }
+ return destination;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Resolves the directory where the web application' context.xml files are
+ * placed. Typically this is the Host's configuration directory.
+ *
+ * @param mainConfigDir
+ * the main Tomcat's configuration directory
+ * @return the directory where the web applications' context.xml files are
+ * placed.
+ */
+ public static File resolveWebappConfigDir(File mainConfigDir, Host host) {
+ mainConfigDir = mainConfigDir != null ? mainConfigDir : new File(DEFAULT_CONFIG_DIRECTORY);
+
+ File configLocation = mainConfigDir;
+
+ Container parent = host.getParent();
+ if ((parent != null) && (parent instanceof Engine)) {
+ configLocation = new File(configLocation, parent.getName());
+ }
+
+ return new File(configLocation, host.getName());
+ }
+
+ private static String formatContextPath(String contextPath) {
+ // Multi-level context paths may be defined using #, e.g. foo#bar.xml
+ // for a context path of /foo/bar.
+ if (contextPath.equals(ROOT_PATH)) {
+ contextPath = ROOT_CONTEXT_FILE;
+ } else if (SLASH_SEPARATOR == contextPath.charAt(0)) {
+ contextPath = contextPath.substring(1);
+ }
+ return contextPath.replace(SLASH_SEPARATOR, HASH_SEPARATOR);
+ }
+
+ private static void copyFile(InputStream source, File destination) throws IOException {
+ destination.getParentFile().mkdirs();
+
+ OutputStream outputStream = null;
+ try {
+ outputStream = new FileOutputStream(destination);
+ byte[] buffer = new byte[1024];
+ int read;
+ while ((read = source.read(buffer)) > 0) {
+ outputStream.write(buffer, 0, read);
+ }
+ } finally {
+ IOUtils.closeQuietly(source);
+ IOUtils.closeQuietly(outputStream);
+ }
+ }
+
+ private static String getRelativePath(File file) {
+ return new File(".").toURI().relativize(file.toURI()).toString();
+ }
+}
diff --git a/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocatorTests.java b/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocatorTests.java
index eba96a5..004129a 100644
--- a/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocatorTests.java
+++ b/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/TomcatConfigLocatorTests.java
@@ -21,7 +21,10 @@ import static org.easymock.EasyMock.createNiceMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import java.io.File;
import java.net.URL;
import java.util.Vector;
@@ -78,6 +81,27 @@ public class TomcatConfigLocatorTests {
TomcatConfigLocator.resolveConfigFile(mockContext);
}
+
+ @Test
+ public void testResolveConfigDir() throws Exception {
+ URL existingUrl = new URL("file:src/test/resources/server.xml");
+ URL nonexistingUrl = new URL("file:src/test/resources/server1.xml");
+
+ BundleContext mockContext = createMock(BundleContext.class);
+ expect(mockContext.getProperty(TomcatConfigLocator.CONFIG_PATH_FRAMEWORK_PROPERTY)).andReturn(
+ (new File(existingUrl.getPath())).getAbsolutePath()).andReturn(
+ (new File(nonexistingUrl.getPath())).getAbsolutePath()).andReturn(null);
+
+ replay(mockContext);
+
+ String result = "src" + File.separator + "test" + File.separator + "resources";
+
+ assertTrue(TomcatConfigLocator.resolveConfigDir(mockContext).getAbsolutePath().endsWith(result));
+ assertEquals(null, TomcatConfigLocator.resolveConfigDir(mockContext));
+ assertEquals(null, TomcatConfigLocator.resolveConfigDir(mockContext));
+
+ verify(mockContext);
+ }
private BundleContext createMockBundleContext(Bundle mockBundle) {
BundleContext mockContext = createNiceMock(BundleContext.class);
diff --git a/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocatorTest.java b/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocatorTest.java
new file mode 100755
index 0000000..1dd19c9
--- /dev/null
+++ b/org.eclipse.gemini.web.tomcat/src/test/java/org/eclipse/gemini/web/tomcat/internal/WebappConfigLocatorTest.java
@@ -0,0 +1,193 @@
+package org.eclipse.gemini.web.tomcat.internal;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Engine;
+import org.apache.catalina.Host;
+import org.eclipse.gemini.web.core.spi.ServletContainerException;
+import org.eclipse.virgo.util.io.IOUtils;
+import org.junit.Before;
+import org.junit.Test;
+
+public class WebappConfigLocatorTest {
+ private static final String CONTEXT_PATH_1 = "test";
+ private static final String CONTEXT_PATH_2 = "test1";
+ private static final String CONTEXT_PATH_3 = "/";
+ private static final String CONTEXT_PATH_4 = "/test/test";
+ private static final String CONTEXT_PATH_5 = "test/test";
+
+ private static final String CONFIG_FILE_LOCATION_1 = "file:src/test/resources/test.xml";
+ private static final String CONFIG_FILE_LOCATION_2 = "file:src/test/resources/META-INF/context.xml";
+ private static final String CONFIG_FILE_LOCATION_3 = "file:target/test-classes/test1.xml";
+ private static final String CONFIG_FILE_LOCATION_4 = "file:target/test-classes/ROOT.xml";
+ private static final String CONFIG_FILE_LOCATION_5 = "file:target/test-classes/test%23test.xml";
+
+ private static final String CONFIG_DIR_LOCATION_1 = "file:src/test/resources";
+ private static final String CONFIG_DIR_LOCATION_2 = "file:src/test";
+ private static final String CONFIG_DIR_LOCATION_3 = "file:target/test-classes";
+
+ private static final String CORRUPTED_JAR_NAME = "file:target/test-classes/corrupted.jar";
+ private static final String JAR_NAME_1 = "file:target/test-classes/test1.jar";
+ private static final String JAR_NAME_2 = "file:target/test-classes/test2.jar";
+ private static final String JAR_ENTRY_NAME = "META-INF/context.xml";
+
+ private static final String HOST_NAME = "localhost";
+ private static final String ENGINE_NAME = "Catalina";
+
+ @Before
+ public void setUp() throws Exception {
+ URL urlFile2 = new URL(CONFIG_FILE_LOCATION_2);
+ URL jarFile1 = new URL(JAR_NAME_1);
+ URL jarFile2 = new URL(JAR_NAME_2);
+ URL corruptedJarFile = new URL(CORRUPTED_JAR_NAME);
+ new File(corruptedJarFile.getPath()).createNewFile();
+
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+
+ FileOutputStream stream = null;
+ JarOutputStream out = null;
+ FileInputStream file = null;
+ try {
+ stream = new FileOutputStream(jarFile1.getPath());
+ out = new JarOutputStream(stream, new Manifest());
+ file = new FileInputStream(new File(urlFile2.getPath()));
+ JarEntry jarAdd = new JarEntry(JAR_ENTRY_NAME);
+ out.putNextEntry(jarAdd);
+ while ((bytesRead = file.read(buffer)) != -1) {
+ out.write(buffer, 0, bytesRead);
+ }
+ out.closeEntry();
+ } finally {
+ IOUtils.closeQuietly(file);
+ IOUtils.closeQuietly(out);
+ IOUtils.closeQuietly(stream);
+ }
+
+ try {
+ stream = new FileOutputStream(jarFile2.getPath());
+ out = new JarOutputStream(stream, new Manifest());
+ } finally {
+ IOUtils.closeQuietly(out);
+ IOUtils.closeQuietly(stream);
+ }
+ }
+
+ @Test
+ public void testResolveWebappContextXml() throws Exception {
+ URL urlFile1 = new URL(CONFIG_FILE_LOCATION_1);
+ URL urlDir1 = new URL(CONFIG_DIR_LOCATION_1);
+ // context.xml exists in the configuration directory
+ assertEquals(new File(urlFile1.getPath()), WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_1, null,
+ new File(urlDir1.getPath())));
+
+ URL urlFile2 = new URL(CONFIG_FILE_LOCATION_2);
+ URL urlDir2 = new URL(CONFIG_DIR_LOCATION_2);
+ // context.xml does not exist in the configuration directory, but exists
+ // in doc base
+ // doc base is directory
+ assertEquals(new File(urlFile2.getPath()), WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_2, urlDir1
+ .getPath(), new File(urlDir1.getPath())));
+ // context.xml does not exist in the configuration directory and in doc
+ // base
+ // doc base is directory
+ assertEquals(null, WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_2, urlDir2.getPath(), new File(
+ urlDir1.getPath())));
+
+ try {
+ // context.xml does not exist in the configuration directory, doc
+ // base is jar and does not exist
+ URL corruptedJarFile = new URL(CORRUPTED_JAR_NAME);
+ WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_2, corruptedJarFile.getPath(), new File(urlDir1
+ .getPath()));
+ } catch (ServletContainerException e) {
+ assertTrue(e.getCause() instanceof IOException);
+ }
+
+ URL jarFile1 = new URL(JAR_NAME_1);
+ URL jarFile2 = new URL(JAR_NAME_2);
+ URL urlDir3 = new URL(CONFIG_DIR_LOCATION_3);
+ URL urlFile3 = new URL(CONFIG_FILE_LOCATION_3);
+ // context.xml does not exist in the configuration directory, but exists
+ // in doc base
+ // doc base is jar
+ // copy will be performed
+ assertEquals(new File(urlFile3.getPath()), WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_2, jarFile1
+ .getPath(), new File(urlDir3.getPath())));
+ // context.xml does not exist in the configuration directory and in doc
+ // base
+ // doc base is jar
+ assertEquals(null, WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_2, jarFile2.getPath(), new File(
+ urlDir1.getPath())));
+
+ URL urlFile4 = new URL(CONFIG_FILE_LOCATION_4);
+ URL urlFile5 = new URL(CONFIG_FILE_LOCATION_5);
+ // different types of context path
+ assertEquals(new File(urlFile4.getPath()), WebappConfigLocator.resolveWebappContextXml(CONTEXT_PATH_3, jarFile1
+ .getPath(), new File(urlDir3.getPath())));
+ assertEquals(new File(urlFile5.toURI().getSchemeSpecificPart()), WebappConfigLocator.resolveWebappContextXml(
+ CONTEXT_PATH_4, jarFile1.getPath(), new File(urlDir3.getPath())));
+ assertEquals(new File(urlFile5.toURI().getSchemeSpecificPart()), WebappConfigLocator.resolveWebappContextXml(
+ CONTEXT_PATH_5, jarFile1.getPath(), new File(urlDir3.getPath())));
+ }
+
+ @Test
+ public void testResolveWebappConfigDir() {
+ Host mockHost = createMock(Host.class);
+ Engine mockEngine = createMock(Engine.class);
+ Container mockContainer = createMock(Container.class);
+ expect(mockHost.getParent()).andReturn(mockEngine).andReturn(mockContainer).andReturn(null).andReturn(
+ mockEngine).andReturn(mockContainer).andReturn(null);
+ expect(mockHost.getName()).andReturn(HOST_NAME).times(6);
+ expect(mockEngine.getName()).andReturn(ENGINE_NAME).times(2);
+
+ replay(mockHost, mockEngine);
+
+ File configDir = new File("");
+ File expected = new File(configDir, ENGINE_NAME);
+ expected = new File(expected, HOST_NAME);
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(configDir, mockHost));
+
+ expected = new File(configDir, HOST_NAME);
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(configDir, mockHost));
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(configDir, mockHost));
+
+ configDir = new File(WebappConfigLocator.DEFAULT_CONFIG_DIRECTORY);
+ expected = new File(configDir, ENGINE_NAME);
+ expected = new File(expected, HOST_NAME);
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(null, mockHost));
+
+ expected = new File(configDir, HOST_NAME);
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(null, mockHost));
+ assertEquals(expected, WebappConfigLocator.resolveWebappConfigDir(null, mockHost));
+
+ verify(mockHost, mockEngine);
+ }
+
+ @Test
+ public void testResolveDefaultContextXml() throws Exception {
+ assertEquals(null, WebappConfigLocator.resolveDefaultContextXml(null));
+
+ URL urlFile = new URL(CONFIG_FILE_LOCATION_2);
+ assertEquals(urlFile.getPath(), WebappConfigLocator.resolveDefaultContextXml(new File(urlFile.getPath())
+ .getParentFile()));
+
+ assertEquals(null, WebappConfigLocator.resolveDefaultContextXml(new File(urlFile.getPath()).getParentFile()
+ .getParentFile()));
+ }
+}
diff --git a/org.eclipse.gemini.web.tomcat/src/test/resources/META-INF/context.xml b/org.eclipse.gemini.web.tomcat/src/test/resources/META-INF/context.xml
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/org.eclipse.gemini.web.tomcat/src/test/resources/META-INF/context.xml
diff --git a/org.eclipse.gemini.web.tomcat/src/test/resources/test.xml b/org.eclipse.gemini.web.tomcat/src/test/resources/test.xml
new file mode 100755
index 0000000..e3e359d
--- /dev/null
+++ b/org.eclipse.gemini.web.tomcat/src/test/resources/test.xml
@@ -0,0 +1,5 @@
+<Context crossContext="true"
+ privileged="true"
+ reloadable="true"
+ useHTTPOnly="true"
+/> \ No newline at end of file