bug 373202: Provide test for JarScannerCustomizer.
diff --git a/build-web-container/build.xml b/build-web-container/build.xml
index 11b31bb..55d5fa1 100644
--- a/build-web-container/build.xml
+++ b/build-web-container/build.xml
@@ -34,6 +34,7 @@
<pathelement location="../test-bundles/war-with-context-xml-custom-classloader"/>
<pathelement location="../test-bundles/war-with-context-xml-cross-context"/>
<pathelement location="../test-bundles/war-with-annotations"/>
+ <pathelement location="../test-bundles/customizer-bundle"/>
</path>
<path id="doc.bundles">
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 8d7f08a..a702605 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
@@ -91,6 +91,8 @@
private static final String LOCATION_WAR_WITH_ANNOTATIONS = "../org.eclipse.gemini.web.test/target/resources/war-with-annotations.war?Web-ContextPath=/war-with-annotations";
+ private static final String LOCATION_BUNDLE_CUSTOMIZER = "file:../org.eclipse.gemini.web.test/target/resources/customizer-bundle.jar";
+
private BundleContext bundleContext;
private ServletContainer container;
@@ -504,6 +506,25 @@
}
@Test
+ public void testCustomizers() throws Exception {
+ Bundle customizer = this.bundleContext.installBundle(LOCATION_BUNDLE_CUSTOMIZER);
+ customizer.start();
+
+ Bundle bundle = this.bundleContext.installBundle(LOCATION_WAR_WITH_SERVLET);
+ bundle.start();
+
+ WebApplicationHandle handle = this.container.createWebApplication("/war-with-servlet", bundle);
+ this.container.startWebApplication(handle);
+ try {
+ validateURL("http://localhost:8080/war-with-servlet/CustomServlet");
+ } finally {
+ this.container.stopWebApplication(handle);
+ bundle.uninstall();
+ customizer.uninstall();
+ }
+ }
+
+ @Test
public void testServletContainerWithCustomDefaultWebXml() throws Exception {
File tomcatServerXml = new File("target/config/tomcat-server.xml");
createFileWithContent(tomcatServerXml, "");
diff --git a/test-bundles/build.properties b/test-bundles/build.properties
index 9008bf0..6c4d378 100644
--- a/test-bundles/build.properties
+++ b/test-bundles/build.properties
@@ -5,7 +5,7 @@
ivy.cache.dir=${basedir}/../../${ivy.cache}
integration.repo.dir=${basedir}/../../integration-repo
disable.bundlor=true
-source.version=1.5
+source.version=1.6
test.vm.args= -Xmx1024M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError
findbugs.enforce=true
clover.enforce=true
diff --git a/test-bundles/customizer-bundle/.classpath b/test-bundles/customizer-bundle/.classpath
new file mode 100755
index 0000000..12d699e
--- /dev/null
+++ b/test-bundles/customizer-bundle/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="var" path="WEB_CONTAINER_IVY_CACHE/org.apache.tomcat/com.springsource.org.apache.tomcat.api/7.0.21/com.springsource.org.apache.tomcat.api-7.0.21.jar" sourcepath="/WEB_CONTAINER_IVY_CACHE/org.apache.tomcat/com.springsource.org.apache.tomcat.api/7.0.21/com.springsource.org.apache.tomcat.api-sources-7.0.21.jar"/>
+ <classpathentry kind="var" path="WEB_CONTAINER_IVY_CACHE/org.eclipse.osgi/org.eclipse.osgi/3.7.0.v20110613/org.eclipse.osgi-3.7.0.v20110613.jar" sourcepath="/WEB_CONTAINER_IVY_CACHE/org.eclipse.osgi/org.eclipse.osgi/3.7.0.v20110613/org.eclipse.osgi-sources-3.7.0.v20110613.jar"/>
+ <classpathentry kind="var" path="WEB_CONTAINER_IVY_CACHE/org.eclipse.gemini.web/org.eclipse.gemini.web.tomcat/2.1.0.M02/org.eclipse.gemini.web.tomcat-2.1.0.M02.jar" sourcepath="/WEB_CONTAINER_IVY_CACHE/org.eclipse.gemini.web/org.eclipse.gemini.web.tomcat/2.1.0.M02/org.eclipse.gemini.web.tomcat-sources-2.1.0.M02.jar"/>
+ <classpathentry kind="var" path="WEB_CONTAINER_IVY_CACHE/javax.servlet/javax.servlet/3.0.0.v201103241009/javax.servlet-3.0.0.v201103241009.jar" sourcepath="/WEB_CONTAINER_IVY_CACHE/javax.servlet/javax.servlet/3.0.0.v201103241009/javax.servlet-sources-3.0.0.v201103241009.jar"/>
+ <classpathentry kind="output" path="target"/>
+</classpath>
diff --git a/test-bundles/customizer-bundle/.project b/test-bundles/customizer-bundle/.project
new file mode 100755
index 0000000..d713fcc
--- /dev/null
+++ b/test-bundles/customizer-bundle/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>customizer-bundle</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/test-bundles/customizer-bundle/build.xml b/test-bundles/customizer-bundle/build.xml
new file mode 100755
index 0000000..be1464e
--- /dev/null
+++ b/test-bundles/customizer-bundle/build.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="customizer-bundle">
+
+ <property file="${basedir}/../build.properties"/>
+ <property file="${basedir}/../../build.versions"/>
+ <property name="jar.output.dir" value="${basedir}/../../org.eclipse.gemini.web.test/target/resources"/>
+ <import file="${basedir}/../../virgo-build/standard/default.xml"/>
+
+</project>
diff --git a/test-bundles/customizer-bundle/ivy.xml b/test-bundles/customizer-bundle/ivy.xml
new file mode 100755
index 0000000..6980ccf
--- /dev/null
+++ b/test-bundles/customizer-bundle/ivy.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="http://ivyrep.jayasoft.org/ivy-doc.xsl"?>
+<ivy-module
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="http://incubator.apache.org/ivy/schemas/ivy.xsd"
+ version="1.3">
+
+ <info organisation="org.eclipse.gemini.web" module="${ant.project.name}"/>
+
+ <configurations>
+ <include file="${virgo.build.dir}/common/default-ivy-configurations.xml"/>
+ </configurations>
+
+ <publications>
+ <artifact name="${ant.project.name}"/>
+ <artifact name="${ant.project.name}-sources" type="src" ext="jar"/>
+ </publications>
+
+ <dependencies>
+ <dependency org="javax.servlet" name="javax.servlet" rev="${javax.servlet}" conf="compile->runtime"/>
+ <dependency org="org.apache.tomcat" name="com.springsource.org.apache.tomcat.api" rev="${org.apache.tomcat}" conf="compile->runtime"/>
+ <dependency org="org.eclipse.osgi" name="org.eclipse.osgi" rev="${org.eclipse.osgi}" conf="compile->runtime"/>
+ <dependency org="org.eclipse.gemini.web" name="org.eclipse.gemini.web.tomcat" rev="2.1.0.M02" conf="compile->runtime"/>
+ </dependencies>
+
+</ivy-module>
diff --git a/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Activator.java b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Activator.java
new file mode 100755
index 0000000..72148d5
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Activator.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web;
+
+import org.eclipse.gemini.web.tomcat.spi.ClassLoaderCustomizer;
+import org.eclipse.gemini.web.tomcat.spi.JarScannerCustomizer;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class Activator implements BundleActivator {
+
+ private ServiceRegistration<?> sr;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ this.sr = context.registerService(new String[] { ClassLoaderCustomizer.class.getName(), JarScannerCustomizer.class.getName() },
+ new Customizer(), null);
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ this.sr.unregister();
+ }
+
+}
diff --git a/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleJarScanner.java b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleJarScanner.java
new file mode 100755
index 0000000..1157648
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleJarScanner.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.JarScannerCallback;
+import org.eclipse.osgi.baseadaptor.BaseData;
+import org.eclipse.osgi.baseadaptor.bundlefile.BundleFile;
+import org.eclipse.osgi.framework.adaptor.BundleData;
+import org.eclipse.osgi.framework.internal.core.BundleHost;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+public class BundleJarScanner implements JarScanner {
+
+ private static final String JAR_URL_SUFFIX = "!/";
+
+ private static final String JAR_URL_PREFIX = "jar:";
+
+ private static final String REFERENCE_URL_PREFIX = "reference";
+
+ @Override
+ public void scan(ServletContext servletContext, ClassLoader classLoader, JarScannerCallback jarScannerCallback, Set<String> jarsToSkip) {
+ Bundle bundle = FrameworkUtil.getBundle(this.getClass());
+ scanBundle(bundle, jarScannerCallback);
+ }
+
+ private void scanBundle(Bundle bundle, JarScannerCallback callback) {
+ File bundleFile = resolve(bundle);
+ if (bundleFile != null) {
+ scanBundleFile(bundleFile, callback);
+ } else {
+ scanJarUrlConnection(bundle, callback);
+ }
+ }
+
+ private void scanJarUrlConnection(Bundle bundle, JarScannerCallback callback) {
+ URL bundleUrl;
+ String bundleLocation = bundle.getLocation();
+ try {
+ bundleUrl = new URL(bundleLocation);
+ if (REFERENCE_URL_PREFIX.equals(bundleUrl.getProtocol())) {
+ bundleUrl = new URL(JAR_URL_PREFIX + bundleUrl.getFile() + JAR_URL_SUFFIX);
+ } else {
+ bundleUrl = new URL(JAR_URL_PREFIX + bundleLocation + JAR_URL_SUFFIX);
+ }
+ } catch (MalformedURLException e) {
+ System.out.println("Failed to create jar: url for bundle location " + bundleLocation);
+ return;
+ }
+
+ scanBundleUrl(bundleUrl, callback);
+ }
+
+ private void scanBundleFile(File bundleFile, JarScannerCallback callback) {
+ if (bundleFile.isDirectory()) {
+ try {
+ callback.scan(bundleFile);
+ } catch (IOException e) {
+ System.out.println("Failure when attempting to scan bundle file '" + bundleFile + "':" + e.getMessage());
+ }
+ } else {
+ URL bundleUrl;
+ try {
+ bundleUrl = new URL(JAR_URL_PREFIX + bundleFile.toURI().toURL() + JAR_URL_SUFFIX);
+ } catch (MalformedURLException e) {
+ System.out.println("Failed to create jar: url for bundle file " + bundleFile);
+ return;
+ }
+ scanBundleUrl(bundleUrl, callback);
+ }
+ }
+
+ private void scanBundleUrl(URL url, JarScannerCallback callback) {
+ try {
+ URLConnection connection = url.openConnection();
+
+ if (connection instanceof JarURLConnection) {
+ callback.scan((JarURLConnection) connection);
+ }
+ } catch (IOException e) {
+ System.out.println("Failure when attempting to scan bundle via jar URL '" + url + "':" + e.getMessage());
+ }
+ }
+
+ private File resolve(Bundle bundle) {
+ BundleFile bundleFile = getBundleFile(bundle);
+ if (bundleFile != null) {
+ File file = bundleFile.getBaseFile();
+ System.out.println("Resolved bundle '" + bundle.getSymbolicName() + "' to file '" + file.getAbsolutePath() + "'");
+ return file;
+ }
+ return null;
+ }
+
+ private BundleFile getBundleFile(Bundle bundle) {
+ if (bundle instanceof BundleHost) {
+ BundleHost bh = (BundleHost) bundle;
+ BundleData bundleData = bh.getBundleData();
+ if (bundleData instanceof BaseData) {
+ return ((BaseData) bundleData).getBundleFile();
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleServletContainerInitializer.java b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleServletContainerInitializer.java
new file mode 100755
index 0000000..90c1861
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/BundleServletContainerInitializer.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web;
+
+import java.util.Set;
+
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+public class BundleServletContainerInitializer implements ServletContainerInitializer {
+
+ @Override
+ public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
+ ServletRegistration servletRegistration = ctx.addServlet("CustomServlet", new CustomServlet());
+ servletRegistration.addMapping("/CustomServlet");
+ }
+
+}
diff --git a/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/CustomServlet.java b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/CustomServlet.java
new file mode 100755
index 0000000..5f0abb8
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/CustomServlet.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class CustomServlet extends HttpServlet {
+
+ private static final long serialVersionUID = 3476948383756233572L;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ resp.getWriter().println("Servlet added by ServletContainerInitializer.");
+ }
+
+}
diff --git a/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Customizer.java b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Customizer.java
new file mode 100755
index 0000000..720792e
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/java/org/eclipse/gemini/web/Customizer.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2012 SAP AG
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Apache License v2.0 which accompanies this distribution.
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Apache License v2.0 is available at
+ * http://www.opensource.org/licenses/apache2.0.php.
+ * You may elect to redistribute this code under either of these licenses.
+ *
+ * Contributors:
+ * Violeta Georgieva - initial contribution
+ *******************************************************************************/
+
+package org.eclipse.gemini.web;
+
+import java.lang.instrument.ClassFileTransformer;
+
+import org.apache.tomcat.JarScanner;
+import org.eclipse.gemini.web.tomcat.spi.ClassLoaderCustomizer;
+import org.eclipse.gemini.web.tomcat.spi.JarScannerCustomizer;
+import org.osgi.framework.Bundle;
+
+public class Customizer implements ClassLoaderCustomizer, JarScannerCustomizer {
+
+ @Override
+ public ClassLoader[] extendClassLoaderChain(Bundle bundle) {
+ return new ClassLoader[] { this.getClass().getClassLoader() };
+ }
+
+ @Override
+ public void addClassFileTransformer(ClassFileTransformer transformer, Bundle bundle) {
+ // no-op
+ }
+
+ @Override
+ public ClassLoader createThrowawayClassLoader(Bundle bundle) {
+ // no-op
+ return null;
+ }
+
+ @Override
+ public JarScanner[] extendJarScannerChain(Bundle bundle) {
+ return new JarScanner[] { new BundleJarScanner() };
+ }
+}
\ No newline at end of file
diff --git a/test-bundles/customizer-bundle/src/main/resources/META-INF/MANIFEST.MF b/test-bundles/customizer-bundle/src/main/resources/META-INF/MANIFEST.MF
new file mode 100755
index 0000000..a33c08a
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1,16 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-SymbolicName: Customizer-bundle
+Bundle-Version: 1.0.0
+Import-Package: org.apache.tomcat,
+ org.eclipse.gemini.web.tomcat.spi,
+ org.osgi.framework,
+ javax.servlet,
+ javax.servlet.http,
+ org.eclipse.osgi.baseadaptor,
+ org.eclipse.osgi.baseadaptor.bundlefile,
+ org.eclipse.osgi.framework.adaptor,
+ org.eclipse.osgi.framework.internal.core
+Bundle-Activator: org.eclipse.gemini.web.Activator
+
+
diff --git a/test-bundles/customizer-bundle/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/test-bundles/customizer-bundle/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
new file mode 100755
index 0000000..2c6aa78
--- /dev/null
+++ b/test-bundles/customizer-bundle/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer
@@ -0,0 +1 @@
+org.eclipse.gemini.web.BundleServletContainerInitializer
\ No newline at end of file
diff --git a/test-bundles/customizer-bundle/template.mf b/test-bundles/customizer-bundle/template.mf
new file mode 100755
index 0000000..eb49210
--- /dev/null
+++ b/test-bundles/customizer-bundle/template.mf
@@ -0,0 +1,10 @@
+Bundle-ManifestVersion: 2
+Bundle-Name: Customizer-bundle
+Bundle-SymbolicName: Customizer-bundle
+Bundle-Version: $version
+Import-Template: org.eclipse.gemini.web.*;version="${version}",
+ org.apache.tomcat.*;version="${org.apache.tomcat}",
+ org.osgi.framework.*;version="0",
+ org.eclipse.osgi.*;version="0",
+ javax.servlet.*;version="3.0.0"
+Bundle-Activator: org.eclipse.gemini.web.Activator
diff --git a/test-bundles/war-with-servlet/src/main/webapp/WEB-INF/web.xml b/test-bundles/war-with-servlet/src/main/webapp/WEB-INF/web.xml
index 094445d..2a746f3 100644
--- a/test-bundles/war-with-servlet/src/main/webapp/WEB-INF/web.xml
+++ b/test-bundles/war-with-servlet/src/main/webapp/WEB-INF/web.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
- version="2.5">
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
<servlet>