What happened to addLifeCycleListener in Jetty 10? - jetty

We used to have code that would bootstrap Google Guice on the startup of our jetty embedded server.
// add a lifecycle listener to bootstrap injector on startup
svr.addLifeCycleListener(new AbstractLifeCycle.AbstractLifeCycleListener() {
#Override
public void lifeCycleStarted(LifeCycle event) {
System.out.println("Bootstrapping Guice injector ...");
Guice.createInjector(new GreeterServletModule(), new GreeterAppModule());
}
});
Now when we try to upgrade to Jetty 10 it says addLifeCycleListener no longer exists.

AbstractLifeCycle.AbstractLifeCycleListener is an EventListener.
use LifeCycle.addEventListener(listener).
Incidentally, the normal way to bootstrap Guice is to extend the com.google.inject.servlet.GuiceServletContextListener and add your extension to the ServletContext listeners?
This is how Google recommends it be done, and is also the way that Google themselves initialize Guice within their own frameworks (like Google App Engine).
Example from Google Cloud Platform Java Samples Project - EchoGuiceListener.java
package com.mycompany;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
public class GreeterGuiceListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new GreeterServletModule(), new GreeterAppModule());
}
}
with ...
ServletContextHandler contextHandler = new ServletContextHandler()
contextHandler.addEventListener(new GreeterGuiceListener());
// ... other init ...
server.start();

Related

Does webjob SDK TimerTrigger support Dependency Injection?

I am using .net core 6 WebJob SDK Version 4.0.1:
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions"Version="4.0.1" />
I added the following line to my webjob setup code:
builder.ConfigureServices(s => s.AddSingleton<MyClass>());
I have a timer trigger like this:
public class TimerFunctions
{
public void TimerTriggerTest([TimerTrigger("*/5 * * * * *")] TimerInfo myTimer,
ILogger logger,
MyClass diTest
)
{
logger.LogInformation("TimerTrigger");
}
}
When run my WebJob project locally, I get the following error:
System.InvalidOperationException: Cannot bind parameter 'diTest' to type MyClass. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).
Yes, the TimerTrigger in the Azure WebJobs SDK does support Dependency Injection (DI). You can use DI to inject dependencies into your timer trigger function by using the [Inject] attribute.
For example, you could use DI to inject a service or repository into your timer trigger function, like this:
public class MyTimerTrigger
{
private readonly IMyService _myService;
public MyTimerTrigger(IMyService myService)
{
_myService = myService;
}
[FunctionName("MyTimerTrigger")]
public async Task Run([TimerTrigger("0 */5 * * * *")] TimerInfo timer)
{
// Use the injected service here
await _myService.DoWorkAsync();
}
}

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.

How to do Unit Test with Dependency Injection .net Core 2

I start to develop a new web application, I create a Domain Object, Inteface, DAL and BLL...
I would like to test all before use that.
If I use the developed function in web application in .net core 2 I put in Startup.cs some code like this :
public void ConfigureServices(IServiceCollection services)
{
**services.AddTransient<ITableOfTableRepository, DBTableOfTableRepository>();**
services.AddMvc();
services.AddSingleton<IConfiguration>(Configuration);
}
And in my Controller add this code
public class TablesController : Controller
{
private readonly ITableOfTableRepository _repository;
public TablesController(ITableOfTableRepository repository)
{
this._repository = repository;
}
How to do a UnitTest project for testing all before of the use in web application?
How to use dependency Injection in unit test?
BR
If you are trying to develop in a test first approach...
You will pass by several steps:
Your test is not compiling because you need to write a controller action and create an interface
Once you created an interface you could mock/stub it (using framework like NSubstitute or others) and inject when you create the controller
var userService = Substitute.For();
...
var controller = new MyController(userService)
you write the controller code for your test to pass

embedded jetty ignoring classes packaged in my war

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

How to write a test for GWT servlet?

I have an GWT application, with few servlets on the server side. I would like to test those servlets (without the need to make GUI tests with Selenium, or any other web-based framework). Or in other words I want the test to simulate the client side of GWT.
The natural challenges with testing the servlets are:
Starting the webserver,
Simulation of client,
Servlets return immediately, passing the value to AsyncCallback object.
So far, I've been able to figure out (although this is still not tested), that:
1. I can start the container by extending GWTTestCase
3. I have found a google doc about asynchronous testing, so it is possible to wait for the async callback. Google docs are also mentioning this:
Server side testing
The tests described above are intended to assist with testing client side code. The test case wrapper GWTTestCase will launch either a development mode session or a web browser to test the generated JavaScript. On the other hand, server side code runs as native Java in a JVM without being translated to JavaScript, so it is not necessary to run tests of server side code using GWTTestCase as the base class for your tests. Instead, use JUnit's TestCase and other related classes directly when writing tests for your application's server side code. That said, you may want both GWTTestCase and TestCase coverage of code that will be used on both the client and the server.
But there are no examples or more in-depth explanation how to achieve this.
I haven't figured out how to simulate the client... Any ideas how can I do that?
Or, if this is not the way to do this, is there any other way? I would prefer to use native GWT classes, not not some 3rd party frameworks for testing the servlets.
Thanks!
How about using an embedded Jetty instance... The Jetty server is inculded in the GWT SDK anyway. So just include the gwt-dev.jar in your project and there you go for the server-side. Emulating the client-side is a whole different story. The problem is the JavaScript to Java serialization/deserialization which happens in GWT magic....
There is a project called gwt-syncproxy that can help here:
http://code.google.com/p/gwt-syncproxy/
In code this could look like this:
import junit.framework.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import com.gdevelop.gwt.syncrpc.SyncProxy;
public class ServletTest {
private Server _server;
#BeforeClass
public void setUp() throws Exception {
_server = new Server(8080);
Context root = new Context(_server, "/", Context.SESSIONS);
root.addServlet(new ServletHolder(new MyServiceImpl()), "/servlet");
_server.start();
}
#Test
public void testMethod1() throws Exception {
MyService rpcService = (MyService) SyncProxy.newProxyInstance(MyService.class, "http://127.0.0.1:8080/servlet", "testMethod1");
String result = rpcService.testMethod1();
Assert.assertTrue(result != null);
}
}