Closed marcocast closed 8 years ago
Hi Marco,
You want to deploy a micro-server application inside an existing Tomcat (or other webserver) along side other war files?
At the moment the micro-boot plugin creates a Microserver front end and a spring-boot backend, so it probably won't give you what you need here.
In order to deploy as a .war file inside a pre-existing container wrap the jar file up in a war file you would need to take the following steps.
In contextInitialized, before the JerseyRestApplication calls Create a MicroserverApp instance don't call run or start (that tries to start a Grizzly or Tomcat), just call the constructor. This will create your SpringContext with all the Microserver beans as well as setting up your Jersey app.
Module m = ()->()->"my-app";
MicroserverApp app = new MicroserverApp(module);
Extract the Spring context via getSpringContext
ApplicationContext springContext = app.getSpringContext();
Extract your Rest Resources from the context
List resources = springContext.getBeansOfType(RestResource.class); //or getBeans with Annotation if you are using the Rest annotation.
Configure Jersey in the web.xml as follows
add org.glassfish.jersey.servlet.ServletContainer as the Jersey Rest Web Servlet
set
javax.ws.rs.Application to com.aol.micro.server.rest.jersey.JerseyRestApplication context to your apps contect providers to your apps provides
Thanks John,
I will give it a go and let you know how it goes.
Cool @kewangie can probably help out here too, he did a lot of the initial work of removing xml while we were still deploying into wars. Some of that info is probably not needed by the way (like setting port on ServerData, but set it on the first pass anyway to keep things simple).
You may also need to create a custom version of com.aol.micro.server.rest.jersey.JerseyRestApplication that accepts the jersey config information from your ServletContextListener directly into a set of static variables. It currently uses ThreadLocal variables which helps with running multiple embedded Jersey apps on a server (via Grizzly).
Almost certainly won't work out of the box for you because of the ThreadLocals. In Grizzly started programmatically, it is called on the app initializer thread. This doesn't happen with Tomcat when use programmatically, so there is a wrapper class which is used instead ( com.aol.micro.server.rest.jersey.CustomJerseyServlet ). There is some chance that might work out of the box, but if not - pass the resources etc into a simple static maps in a custom JerseyRestApplication. We can merge the changes back into the core later.
Hi John,
thank you for your thorough explanation. I am following your steps to understand what we need to do for the customization.
From the explanation I got a few questions:
1) I found in the createApp Method in the GrizzlyApplicationFactory class, a very similar code.
PStack resources = extractor.getRestResources(rootContext);
Environment environment = rootContext.getBean(Environment.class);
environment.assureModule(module);
String fullRestResource = "/" + module.getContext() + "/*";
ServerData serverData = new ServerData(environment.getModuleBean(module).getPort(),
resources,
rootContext, fullRestResource, module);
The difference I see to your code is, that the resources are extracted by the ModulaDataExtractor and you extract a subset of resource with:
List resources = springContext.getBeansOfType(RestResource.class); //or getBeans with Annotation if you are using the Rest annotation.
Did I get that right?
So the ServerData instances only differs in the resources it contains?
2) The JerseyPlugin class returns the JerseySpringIntegrationContextListener, which I need to customize. So I could replace the JerseyPlugin or add another plugin?
3) interface Module has the method
default List<ServletContextListener> getListeners(ServerData data)
Which I could override in a customized (WarModule) class which applies map(fn->fn.apply()) instead of map(fn->fn.apply(data))? Did I get that right?
Thank you John. Please push me on the right track if I am on the wrong one.
Cheers, Tobias
@tobwiens
Hi Tobias,
1) Yes that's right, eventually for the micro-war plugin we would want to extract both types, but to get a working prototype you can just extract Resources by the marker you are using (@Rest or implements RestResource). The GrizzlyApplicationFactory is also extracting property information (port / hostname overrides) and setting up the filters / servlets which we can ignore for now (i.e. use web.xml & server.xml)
2) I would import it for now, so the same classes are available. It won't be triggered as jax-rs configuration is triggered inside the programmatic Grizzly / Tomcat builder code. See my other comment above about the way JerseyRestApplication finds it's resources (I suspect a bit of customization will be required there too).
3) I don't think that code will be called (at least in a first-pass micro-war plugin). As it's a lot simpler to configure Servlets / Filters & Listeners directly in the web.xml. Once we have a working micro-war plugin, we could add a delegating instance of each to allow fuller Microserver configuration to work.
If you create a fork on github - I can take a look at the code you are writing and help out that way too!
Thanks! John
@tobwiens @marcocast
Hey guys -
A completely unorthodox (slightly crazy :) approach would be to try starting Microserver on a different port inside a ServletContextListener, i.e. just move your main method inside the war file. Grizzly especially with NIO can be pretty lightweight, and this would keep your application thread pools separate (I haven't looked at multi-tenant Tomcat in a long time, but looking at the docs I think all apps share an Executor configured per connector).
I like this pragmatic approach :), but our main problem is that our clients sometimes, do not want to open new ports on their servers for security reasons :(
On Mon, Jan 18, 2016 at 11:15 AM, johnmcclean-aol notifications@github.com wrote:
@tobwiens https://github.com/tobwiens @marcocast https://github.com/marcocast
Hey guys -
A completely unorthodox (slightly crazy :) approach would be to try starting Microserver on a different port inside a ServletContextListener, i.e. just move your main method inside the war file. Grizzly especially with NIO can be pretty lightweight, and this would keep your application thread pools separate (I haven't looked at multi-tenant Tomcat in a long time, but looking at the docs I think all apps share an Executor configured per connector).
— Reply to this email directly or view it on GitHub https://github.com/aol/micro-server/issues/152#issuecomment-172487944.
On the web : technical blog http://rdafbn.blogspot.co.uk/ , opensource http://code.google.com/p/grep4j/ , linkedin http://www.linkedin.com/pub/marco-castigliego/0/797/a26
As of Microserver v0.80 it is possible to use Microserver to configure Spring Boot Jersey applications via the micro-spring-boot plugin (note this is a new plugin, micro-boot covers Spring Boot backends and Microserver front-ends).
Fantastic! I will test it and I will let you know.
Is swagger UI embedded as well in this plugin?
Actually the swagger plugin one is that still needs a bit of work to correctly identify the resources, as I didn't integrate in Microserver ContextListeners / Servlets or Filters. I think adding the ContextListener required for the Swagger plugin should be trivial though - I'll do that tomorrow (or possibly next day, but sometime this week for sure) and release v0.80.1.
Also - I need to document this - but if you want to override some of the properties on the Module, you need to make your module a spring bean (this is because I'm passing it to some Spring classes) . Easiest way is to make the main class implement Module and just pass that in to the Microserver app.
Got it working, will release it tomorrow :)
By the way - nice new feature in Cyclops made this a lot easier too
SequenceM.fromIterable(listeners)
.forEachWithError(l->l.contextDestroyed(sce),
e->logger.error(e.getMessage(),e));
micro-spring-boot swagger support released in 0.80.1 - should be in maven central shortly.
We are running a server containing other .war services and we would like to include services created with micro-server as well. Is it possible to generate .war instead of .jar? I know it's possible from spring-boot (https://spring.io/guides/gs/convert-jar-to-war/) , so maybe there is a way to do it using the microboot plugin ?
Thanks guys!