embedded jetty ignoring classes packaged in my war - jetty

I'm trying to run jetty in embedded mode. It appears to be ignoring all the classes bundled in my war file, whether under WFB-INF/classes or WEB-INF/lib.
My startup code:
package rfd;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
public class RfdWar
{
public static void main(String[] args) throws Exception
{
System.setProperty("org.eclipse.jetty.LEVEL", "DEBUG");
Server server = new Server(8080);
org.eclipse.jetty.webapp.Configuration.ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration", "org.eclipse.jetty.plus.webapp.PlusConfiguration");
Resource jettyEnv = Resource.newSystemResource("jetty-env.xml");
XmlConfiguration conf = new XmlConfiguration(jettyEnv.getInputStream());
Object obj = conf.configure();
WebAppContext context = (WebAppContext)obj;
context.setWar("/tmp/thewar.war");
context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();
}
}
My command line:
export JETTYHOME=<my_jetty_home>
JHL=$JETTYHOME/lib
export CLASSPATH=.:$JHL/jetty-server-9.2.10.v20150310.jar:$JHL/jetty-util-9.2.10.v20150310.jar:$JHL/jetty-http-9.2.10.v20150310.jar:$JHL/servlet-api-3.1.jar:$JHL/jetty-io-9.2.10.v20150310.jar:$JHL/jetty-webapp-9.2.10.v20150310.jar:$JHL/jetty-servlet-9.2.10.v20150310.jar:$JHL/jetty-security-9.2.10.v20150310.jar:$JHL/jetty-xml-9.2.10.v20150310.jar:$JHL/jetty-plus-9.2.10.v20150310.jar:$JHL/jetty-jndi-9.2.10.v20150310.jar:$JHL/jsp/javax.servlet.jsp-2.3.2.jar:$JHL/jsp/javax.servlet.jsp-api-2.3.1.jar
java rfd.RfdWar
The server does launch correctly and definitely reads web.xml packaged in the war. But when I try accessing the URL I'm getting an error that my class, that's packaged with the war, is missing.
Is there anything else I need to do to tell jetty to honor the classes packaged in the war?

This command ...
context.setParentLoaderPriority(true);
Basically says that when the webapp is attempting to load a class, the server classpath is checked first, then the webapp's classpath.
So if you happen to have the same classes in both places, the server version will be used, ignoring the one on the webapp.
Set this to false to get honest servlet spec behavior, with all of the WebApp classloader isolation.
Also, this is wrong, in many different ways.
Resource jettyEnv = Resource.newSystemResource("jetty-env.xml");
XmlConfiguration conf = new XmlConfiguration(jettyEnv.getInputStream());
Object obj = conf.configure();
WebAppContext context = (WebAppContext)obj;
The proper way to get jetty-env.xml to be loaded is to use the establish the WebApp and ClassList Configuration that performs this function from within the appropriate classloader and thread scope.
See documentation at https://www.eclipse.org/jetty/documentation/current/jndi-embedded.html
And prior answer at Can't get jetty to read jetty-env.xml

Related

Jetty Server not Working for War with JSPs

I am trying to create a simple jetty server/container that will take a war file and deploy. This is not embedded jetty with spring-boot.
Here is my build.gradle dependencies:
dependencies {
def jettyVersion = "9.4.34.v20201102"
implementation "org.eclipse.jetty:jetty-server:$jettyVersion"
implementation "org.eclipse.jetty:jetty-security:$jettyVersion"
implementation "org.eclipse.jetty:jetty-servlet:$jettyVersion"
implementation "org.eclipse.jetty:jetty-webapp:$jettyVersion"
implementation "org.eclipse.jetty:jetty-annotations:$jettyVersion"
implementation "org.eclipse.jetty:jetty-jmx:$jettyVersion"
}
Here is my main class:
public static void main(String[] args) throws Exception {
Server server = new Server(8080);
MBeanContainer mbContainer = new MBeanContainer(getPlatformMBeanServer());
server.addBean(mbContainer);
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
webapp.setWar(warFile()); // LOGIC TO UPLOAD WAR FILE
webapp.setExtractWAR(true);
Configuration.ClassList classList = Configuration.ClassList.setServerDefault(server);
classList.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/[^/]*servlet-api-[^/]*\\.jar$|.*/javax.servlet.jsp.jstl-.*\\.jar$|.*/[^/]*taglibs.*\\.jar$");
server.setHandler(webapp);
server.start();
server.dumpStdErr();
server.join();
}
However, when I try to go to the app (http://localhost:8080/index), I keep getting the following error message:
URI: /index
STATUS: 500
MESSAGE: JSP support not configured
SERVLET: jsp
There is only one line of error message in the console:
2020-12-11 09:49:51.563:INFO:oejshC.ROOT:qtp2025864991-33: No JSP support. Check that JSP jars are in lib/jsp and that the JSP option has been specified to start.jar
What JSP Jars that it is referring to? I am at a loss as to what dependencies I need to add to make it work for JSPs.
Thx.
You will have to add apache-jsp so that your server will support jsps. If your web app uses jstl, you should also add apache-jstl.
For WebAppContext usage (which is a bit easier to setup than ServletContextHandler usage) you'll need the following artifacts ...
https://search.maven.org/artifact/org.eclipse.jetty/apache-jsp (for the Jetty specific JettyJspServlet which extends from the Jasper JspServlet)
https://search.maven.org/artifact/org.eclipse.jetty/apache-jstl (to support Taglibs custom and standard)
Make sure your org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern can reference the apache-jsp artifact properly, otherwise the internal javax.servlet.ServletContextInitializer will not load properly.
If nothing happens by simply adding those artifacts, you'll need to verify your default descriptor setup on your WebAppContext.setDefaultsDescriptor(String) to ensure that you pass in a resource reference (path or uri) to the Jetty default descriptor XML.
https://github.com/eclipse/jetty.project/blob/jetty-9.4.35.v20201120/jetty-webapp/src/main/config/etc/webdefault.xml
Enabling JSP support in embedded mode can be quite tricky if you use the ServletContextHandler instead of the WebAppContext.
If you ever decide to use the ServletContextHandler instead of a WebAppContext (to have a single fat/uber jar, to speed up load/deploy time, to ease unit testing, etc...), then check out the Jetty maintained example project at ...
https://github.com/jetty-project/embedded-jetty-jsp

Embedded Jetty: ServletContextListener that registers a ServletRequestListener

I am using embedded Jetty v9.4.x and have the following issue:
My server registers a ServletContextListener:
final WebAppContext context = new WebAppContext();
// add listener
context.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
#Override
public void lifeCycleStarting(LifeCycle event) {
ContextHandler.Context ctx = context.getServletContext();
ctx.setExtendedListenerTypes(true);
ctx.addListener("LISTENER_CLASS_NAME");
}
});
My listener gets called on Servet start. However, my context listener registers a ServletRequestListener inside:
servletContext.addListener(foo.MyServletRequestListener.class);
And this fails with the following exception:
java.lang.UnsupportedOperationException
at org.eclipse.jetty.servlet.ServletContextHandler$Context.addListener(ServletContextHandler.java:1506)
And when I looked it seems that context is not enabled (at least, this flags makes an exception to be thrown).
When I run the same application with the web.xml everything works.
How can I let the contextListener register a ServletRequestListener?
edit
There is explict note in Jetty code:
//toggle state of the dynamic API so that the listener cannot use it
This is enabled only on programatically added listeners - using API and not web-xml.
How I can make this work???
There are many different kinds of listeners in Jetty, each with their own specific set of add/remove/get/set methods.
Your AbstractLifeCycleListener is a Jetty LifeCycle listener, applying specifically for the Jetty internal starting/started/stopping/stopped of the various beans within Jetty.
Your implementation of this listener in your question is incomplete and shows a lack of understanding of the LifeCycleEvent (you are not looking for a specific bean to be started), your implementation will run hundreds of times. (once for each bean being started).
The use of ServletContext.addListener() has rules around it, and those specify that it can only be used during the ServletContext initialization phase (not before, not after). The use of ServletContext.addListener() outside of this phase is supposed to throw an IllegalStateException (the javadoc even says so)
The ServletContext.addListener() also has a limited set of servlet Listeners that are allowed to be used with it, far less then the number of listeners types that are valid with a Web App, or can be declared within a WEB-INF/web.xml, or flagged with the #WebListener annotation.
The only way to use the ServletContext.addListener() is from within the webapp itself, using webapp code, from within the webapp's own classloader.
The places to use ServletContext.addListener() are ...
ServletContainerInitializer.onStartup()
ServletContextListener.contextInitialized()
Filter.init()
Servlet.init()
As you can see, all of these locations are defined from within the webapp itself.
The existence of ServletContextHandler.addEventListener(EventListener) is an embedded-jetty work around, which allows the Listener to be added on construction of the ServletContextHandler, but not called until the actual event occurs.
The use of ServletContextHandler.addEventListener(EventListener) is equivalent to using the WEB-INF/web.xml to declare the Listener you are interested in having be used.
Example:
package jetty.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
public class ServletContextListenerExample
{
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
MyContextListener contextListener = new MyContextListener();
context.addEventListener(contextListener);
// for context based static file serving and error handling
context.addServlet(DefaultServlet.class, "/");
HandlerList handlers = new HandlerList();
handlers.addHandler(context);
// for non-context error handling
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
server.join();
}
public static class MyContextListener implements ServletContextListener
{
#Override
public void contextInitialized(ServletContextEvent sce)
{
System.err.printf("MyContextListener.contextInitialized(%s)%n", sce);
sce.getServletContext().addListener(new MyRequestListener());
}
#Override
public void contextDestroyed(ServletContextEvent sce)
{
System.err.printf("MyContextListener.contextDestroyed(%s)%n", sce);
}
}
public static class MyRequestListener implements ServletRequestListener
{
#Override
public void requestDestroyed(ServletRequestEvent sre)
{
System.err.printf("MyRequestListener.requestDestroyed(%s)%n", sre);
}
#Override
public void requestInitialized(ServletRequestEvent sre)
{
System.err.printf("MyRequestListener.requestInitialized(%s)%n", sre);
}
}
}
This will register MyContextListener which implements both javax.servlet.ServletContextListener.
When the ServletContext initialization phase kicks in, the contextInitialized() event is triggered.
The implementation of contextInitalized() then uses the passed in ServletContext to add a new MyRequestListener (which implements javax.servlet.ServletRequestListener) via the ServletContext.addListener() API.
Output of the above, and hitting http://localhost:8080/ from a browser ...
2018-06-28 09:42:06.352:INFO::main: Logging initialized #340ms to org.eclipse.jetty.util.log.StdErrLog
2018-06-28 09:42:06.475:INFO:oejs.Server:main: jetty-9.4.11.v20180605; built: 2018-06-05T18:24:03.829Z; git: d5fc0523cfa96bfebfbda19606cad384d772f04c; jvm 9.0.4+11
MyContextListener.contextInitialized(javax.servlet.ServletContextEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,STARTING}])
2018-06-28 09:42:06.532:INFO:oejsh.ContextHandler:main: Started o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}
2018-06-28 09:42:06.695:INFO:oejs.AbstractConnector:main: Started ServerConnector#4567f35d{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2018-06-28 09:42:06.695:INFO:oejs.Server:main: Started #690ms
MyRequestListener.requestInitialized(javax.servlet.ServletRequestEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}])
MyRequestListener.requestDestroyed(javax.servlet.ServletRequestEvent[source=ServletContext#o.e.j.s.ServletContextHandler#12e61fe6{/,null,AVAILABLE}])
Caution: Be aware that there are many more listener APIs and listener types on Jetty then discussed here, they exist for other features / components with Jetty that are unrelated to your question.
Don't get hung up on them, skip them, ignore them and you'll be fine.

JAVA JAX-WS NullPointerException at javax.xml.ws.Service.getPort(Service.java:188)

I have simple "HelloWorld" web service deployed on jboss under ubuntu.
I have created simple client, but I can't get it to work. I'm getting NullPointerException each time I run the client.
Note that I'm running on Oracle Java 7 under Ubuntu.
Here is the code:
HelloWorldClient.java
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
public class HelloWorldClient {
public static void main(String[] args){
URL url;
try {
url = new URL("http://localhost:8080/WebServiceProject/helloWorld?wsdl");
QName qname = new QName("http:///", "HelloWorldImplService");
Service service = Service.create(url, qname);
HelloWorld hello = service.getPort(HelloWorld.class);
System.out.println(hello.sayHello("mkyong"));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
HelloWorld.java
import javax.jws.WebMethod;
import javax.jws.WebService;
#WebService
public interface HelloWorld {
#WebMethod
public String sayHello(String name);
}
Stacktrace:
Exception in thread "main" java.lang.NullPointerException
at com.sun.xml.internal.ws.model.RuntimeModeler.getPortTypeName(RuntimeModeler.java:1407)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:334)
at com.sun.xml.internal.ws.client.WSServiceDelegate.getPort(WSServiceDelegate.java:354)
at javax.xml.ws.Service.getPort(Service.java:188)
at HelloWorldClient.main(HelloWorldClient.java:18)
The exception is thrown at this line:
HelloWorld hello = service.getPort(HelloWorld.class);
I have had the same problem myself for a few days now, because the WSDL-file (and service) I was using was moved to a new URL. I finally found the solution here:
http://techtracer.com/2007/08/15/jax-ws-jaxp-tutorial-building-a-stockquote-web-service-client/
In short, everything (should have) started working after I re-generated all the auto-generated java and class files with the following command (on Windows/CygWin)
"C:/Program Files/Java/jdk1.8.0_31/bin/wsimport.exe" -keep https://domain.com/path_to_wsdl
I had some extra trouble because some old files were left around and clashing with the newly generated ones, but everything slowly started working after I moved all the old files to the recycle bin.
It can also happen if your web-service's implementation is different than the interface from your project.
If in your project you have HelloWorld.class declaring some methods that are not present on the web-service side, the getPort(HelloWorld.class) call will raise a null pointer exception.
You can double check the HelloWorld.class interface on your application and the one on the web-service itself to make sure they match.

How to access EJB services from a grails standalone client

I've been having problems to access to my EJB services from a standalone client i've developed on grails 2.0.3. The EJB services are deployed on a glassfish server (Java). I tested this code on a netbeans tester class to access the EJBs:
Properties p = new Properties();
p.put("java.naming.factory.initial", "com.sun.enterprise.naming.SerialInitContextFactory");
p.setProperty("java.naming.factory.url.pkgs", "com.sun.enterprise.naming");
p.setProperty("java.naming.factory.state", "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
p.setProperty("org.omg.CORBA.ORBInitialHost", INTEGRATION_IP);
p.setProperty("org.omg.CORBA.ORBInitialPort", CORBA_PORT);
ctx = new InitialContext(p);
try {
this.admAuth = (AdmAuthenticationRemote) this.ctx.lookup(Tester.AUTHENTICATION_SERVICE_JNDI);
}catch(Exception e){
...
}
This Tester.AUTHENTICATION_SERVICE_JNDI is a variable tha contains the path to the deployed service, in this case something like "java:global/..." that represents the address to the service that is being requested. This way of accessing the services works perfectly from the tester, but when i try to do the same from grails doesn't works. I am able to create the context the same way, but when i invoke the ctx.lookup() call i get an exception:
Message: Lookup failed for 'java:global/...' in SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory,
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
Cause: javax.naming.NamingException: Unable to acquire SerialContextProvider for SerialContext[myEnv={java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory,
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl, java.naming.factory.url.pkgs=com.sun.enterprise.naming}
[Root exception is java.lang.RuntimeException: Orb initialization erorr]
The main exception is a naming exception, which means that it failed in the ctx.lookup(), but the cause is the orb initialization exception, which has another exception stack:
java.lang.RuntimeException: Orb initialization erorr
Caused by: java.lang.RuntimeException: java.lang.IllegalArgumentException: Can not set long field com.sun.corba.ee.impl.orb.ORBDataParserImpl.waitForResponseTimeout to java.lang.Integer
Caused by: java.lang.IllegalArgumentException: Can not set long field com.sun.corba.ee.impl.orb.ORBDataParserImpl.waitForResponseTimeout to java.lang.Integer
I'm really lost here. I've been having a lot of problems to get this going on grails, I had to get all glassfish jars (libs and modules) so it could make the InitialContext() call, but now i'm not sure if this is still a jar problem or a configuration problem or what it is.
I know that IllegalArgumentException occurs when u try to assign incompatible types in java, but i'm not setting anything like that, so i assume its an internal method initialization.
So the question is why is this exception coming up??
Is there another way to invoke my services from grails that works better??
The error is that you're trying to run your web application using the tomcat plugin in grails (using the command grails run-app). The problem is that when you try to create the InitialContext (com.sun.enterprise.naming.SerialInitContextFactory) groovy gives you an error casting some types if you're using the client libraries for GF 3.1. (I know that this is the problem, but I really don't know the reason for this. Because in theory this should work)
If you generate the .war file and you deploy in an AppServer, you can connect to your EJBs without problems. And if you deploy it on another GF server you don't have to import any of the client jars.
This will work perfect on production, the only problem is that you must compile and deploy your app on the GF server with every little change, and this is a bit annoying in development.
If you want to work outside of GF and using the command "grails run-app", you must modify two of the .jar GF 3.1 on your remote server, where you have the grails application:
1- The jar file $GLASSFISH_HOME/modules/glassfish-corba-omgapi.jar
You should search in the web the class com.sun.corba.ee.spi.orb.ParserImplBase, and modify this part
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, value);
for this
if (name.equalsIgnoreCase("waitForResponseTimeout")) {
Object newValue = new Long(1800000);
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, newValue);
} else {
Field field = getAnyField(name);
field.setAccessible(true);
field.set(ParserImplBase.this, value);
}
this should resolve the java.lang.IllegalArgumentException
2- The jar file $GLASSFISH_HOME/modules/glassfish-corba-orb.jar
you must delete the javax.rmi.CORBA.PortableRemoteObjectClass class of this library, because this class have conflicts with one used by the grails plugin
PS:
If you do not want to have the GF client jars in your grails application, you can add to the classpath of your client machine the following libraries
$GLASSFISH_HOME/modules/ejb-container.jar
$GLASSFISH_HOME/modules/ejb.security.jar
$GLASSFISH_HOME/modules/management-api.jar
If you use the grails console with the grails run-app command, must modify the configuration file $GRAILS_HOME/conf/groovy-starter.conf whit this
load $GLASSFISH_HOME/modules/ejb-container.jar
load $GLASSFISH_HOME/modules/ejb.security.jar
load $GLASSFISH_HOME/modules/management-api.jar

Weblogic 11 G : Altering default class loading

I have one query regarding Weblogic server 11 G class loading infrastructure.
Lets say I have two application jars named A.jar and B.jar loaded in classpath during server start up.
Both jar contains class say LoadMe.class and sever loads LoadMe.class from jar A.jar by default.
Now I want to alter above default behavior and want to load that class from B.jar instead of A.jar.
How can I do that?
Any help will be appreciated.
Whenever you use LoadMe class for the first time the ClassLoader will try to resolve the dependency using the CLASSPATH.
Now if you have to load the class from B.jar, then you will have to explicitly place path to that jar first and A.jar second in the CLASSPATH. So the ClassLoader will pick the class from B.jar first.
Try this link for more on ClassLoaders
Read this and change the classpath and the problem should be solved
Setting classpath in WebLogic 11G
UPDATE:
System.out.println("Classpath dependency for LoadClass: ");
URLClassLoader classLoader = (URLClassLoader)LoadMe.class.getClassLoader();
System.out.println(Arrays.toString(classLoader.getURLs()));
System.out.println("Classpath dependency for Context: ");
URLClassLoader classLoader1 = (URLClassLoader)Thread.currentThread().getContextClassLoader());
System.out.println(Arrays.toString(classLoader.getURLs()));