I need to load some servlet from jar file and map it to the URL in Tomcat.
Servlet code is
package net.arturik.mymodulepackage;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "QWERTY", urlPatterns = {"/qqq"})
public class QWERTY extends HttpServlet {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
/* TODO output your page here. You may use following sample code. */
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet QWERTY</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Servlet QWERTY at " + request.getContextPath() + "</h1>");
out.println("</body>");
out.println("</html>");
}
}
// <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
public String getServletInfo() {
return "Short description";
}// </editor-fold>
}
Servlet compiled and stored in file MyModulePackage-1.0-SNAPSHOT.jar.
In Java Web App I has ServletContextListenerImpl class:
package net.arturik.testosgispring;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.WebListener;
@WebListener
public class ServletContextListenerImpl implements ServletContextListener {
@Override
public void contextInitialized(final ServletContextEvent sce) {
try {
System.out.println("++++++++++++++");
final ServletContext servletContext = sce.getServletContext();
//////////////////////////////////////////////
String pathToJar = "m:\\myhostingpanel\\myhostingpanel\\Tests\\MyModulePackage\\target\\MyModulePackage-1.0-SNAPSHOT.jar";
JarFile jarFile = new JarFile(pathToJar);
Enumeration e = jarFile.entries();
URL[] urls = {new URL("jar:file:" + pathToJar + "!/")};
URLClassLoader cl = URLClassLoader.newInstance(urls, this.getClass().getClassLoader());
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if (je.isDirectory() || !je.getName().endsWith(".class")) {
continue;
}
// -6 because of .class
String className = je.getName().substring(0, je.getName().length() - 6);
className = className.replace('/', '.');
Class c;
Object obj;
try {
System.out.println("className !!! " + className);
c = cl.loadClass(className);
obj = c.newInstance();
System.out.println(c.getPackage() + " " + c.getName());
Class noparams[] = {};
// Method method = c.getDeclaredMethod("qqq", noparams);
// method.invoke(obj, null);
// MyInter obj1 = (MyInter) c.newInstance();
// obj1.qqq();
System.out.println("registering");
final ServletRegistration.Dynamic dynamic = servletContext.addServlet("QWERTY", c);
dynamic.addMapping("/qqq");
final Map<String, ? extends ServletRegistration> map = servletContext.getServletRegistrations();
for (String key : map.keySet()) {
System.out.println("Registered Servlet: " + map.get(key).getName());
}
System.out.println("end of registering ");
} catch (Exception ex) {
ex.printStackTrace();
}
}
//////////////////////////////////////////////
} catch (IOException ex) {
Logger.getLogger(ServletContextListenerImpl.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void contextDestroyed(final ServletContextEvent sce) {
//NO-OP
}
}
This code got output
++++++++++++++
className !!! net.arturik.mymodulepackage.QWERTY
package net.arturik.mymodulepackage net.arturik.mymodulepackage.QWERTY
registering
Registered Servlet: default
Registered Servlet: jsp
Registered Servlet: QWERTY
Registered Servlet: T1
Registered Servlet: mvc-dispatcher
Registered Servlet: T2
Registered Servlet: T3
end of registering
As we can see - servlet registered successfully.
But if I try to open page /qqq , Tomcat got Exception
22-Nov-2014 02:07:56.846 SEVERE [http-nio-8082-exec-5] org.apache.catalina.core.StandardWrapperValve.invoke Allocate exception for servlet QWERTY
java.lang.ClassNotFoundException: net.arturik.mymodulepackage.QWERTY
As I understand - it is a class visibility problem - my class initialized by URLClassLoader and my class doesn't passed to the main (system) Class Loader.
How can I pass my class, loaded by URLClassLoader to the system class loader for global visibility?