I have spent a few days on this and I still did not find an answer (i did find questions asking for this)
I am coding with java, using a grizzly server (2.3 version) and I've managed to work with many kind of resources (restful classes, java servlets etc).
URI uri = new URI("http://localhost....");
ResourceConfig rc = new ResourceConfig();
rc.registerClasses(aResource.class);
GrizzlyHttpServerFactory.createHttpServer(uri, rc);
My goal though, is to load a whole war file and not individual classes but i have not find a way to do it.
So the question is 'how can i deploy and run a war file inside a grizzly server?'
According to the Grizzly Javadoc you do it like this:
Synchronous Web Server servicing a Servlet
GrizzlyWebServer ws = new GrizzlyWebServer("/var/www");
try {
ServletAdapter sa = new ServletAdapter();
sa.setRootFolder("/Path/To/Exploded/War/File");
sa.setServlet(new MyServlet());
ws.addGrizzlyAdapter(sa);
ws.start();
} catch (IOException ex) {
// Something when wrong.
}
However, as you can see, you first have to "explode" the WAR file; i.e. unpack it into the file system.
You seem to be using the Jersey ResourceConfig class. To make your approach work, I think you would need to do the following:
Unpack the WAR file.
Create a URLClassloader instance that loads from "/WEB-INF/classes" the JARs etc in "/WEB-INF/lib".
Register it by calling ResourceConfig.setClassLoader
For the record, classloading from a packed WAR file is more effort, and apparently gives poor performance. (If you want to see how to do it, Tomcat has this functionality ... disabled by default.)
It's not possible to deploy WAR files to Grizzly 2.x at this point in time.
Related
I have created application in Dropwizard, which is serving REST API to my clients. I used to run this from .jar file on server, everything worked fine.
Now I have requirement to move my application to WildFly, so now I assume that I need to have a WAR instead of JAR, and here comes my problem:
How to write web.xml to my application? What to include in there? Could anyone give me any template or tutorial or some example how it is done in Dropwizard?
I found what I was looking for. It's wizard-in-a-box project that do all the necessary things to build a WAR file.
One of the most important non-functional requirements of any project is the build process in my opinion and that's where I kinda get stuck in my java project, which has just one external dependency, a jdbc compatible database. All the tutorials about spring and deployment out there; I've read them all, but they either say:
run it with gradle bootRun applications.properties (yes works but on a webserver I'm not going to have any properties-files, but JNDI resource for example) or
build a deployable war file with JNDI resources (yes it works on the webserver, but not in my embedded webserver or I'm doing it wrong, but I cannot find any doc about how an embedded tomcat loads a context.xml from outside the jar file).
Now I tried to use the same setup as my server and installed tomcat7 and the #Asyc #Scheduled services run, but no servlets, like a simple /status page should return "OK" just for checking. catalina.out does not show any errors. My /manager from tomcat7-admin says deployment ok, and when I click start: "FAIL - Application at context path /xyz-0.1.0 could not be started
FAIL - Encountered exception org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/xyz-0.1.0]]"
And now I want to make a cut here and throw every "bootstrap" stuff away and start from zero.
So my question is, am I wrong when I say, that the big deal of my deployment is a jdbc JNDI resource provided from the web container, which is called 'jdbc/xyz' and everyone who wants to deploy my war needs that JNDI. That means so matter if you're using wildfly, jboss, tomcat, glassfish or any embedded server: your server impl has to provide that web container and jndi resource to make it run. And I don't want to configure any tomcat, glassfish or whatever implementation in my war.
Is that wrong?
It would be great, if you could help me. I'm playing around with that many weeks now :( and if A works B does not and vice versa. Would it be easier to use JEE?
Thank you.
I need to hot-deploy and -undeploy resources in a Jersey ServletContainer.
There seems to be no way to 'unregister' resources on a ResourceConfig, so the route I'm following is to replace all resources with a new set.
Although the documentation says registerResources on ResourceConfig replaces all resources, browsing through the source code seems to contradict this.
The solution I found was to reload the ServletContainer with an entirely new ResourceConfig.
Set<Class<?>> classes = ...
ResourceConfig config = new ResourceConfig(classes);
container.reload(config);
This works fine until I deploy a resource that results in a ModelValidationException. After that I cannot get the ServletContainer back in a proper state.
If I take a look at the source code:
public void reload(final ResourceConfig configuration) {
try {
containerListener.onShutdown(this);
webComponent = new WebComponent(webComponent.webConfig, configuration);
containerListener = webComponent.appHandler;
containerListener.onReload(this);
containerListener.onStartup(this);
} catch (final ServletException ex) {
LOGGER.log(Level.SEVERE, "Reload failed", ex);
}
}
The ModelValidationException is thrown from the WebComponent constructor.
After that any call to reload results in an exception from the onShutdown method, caused by checkState in the preDestroy method of the ServiceLocatorImpl.
I can avoid the exception by ignoring validation errors
ResourceConfig config = new ResourceConfig(classes);
config.property(ServerProperties.RESOURCE_VALIDATION_IGNORE_ERRORS,
Boolean.TRUE);
container.reload(config);
There is no way now however to find out if there were any errors but to explore the logging, which is just as bad, really.
Per heenenee's comment I tried subclassing ServletContainer, but something like this gives problems because the ResourceConfig cannot be put in two WebComponents.
I tried creating the WebComponent before shutting down, to get an early exit, but this fails the actual reload if there is no error in the resources (because the resourceconfig cannot be modified after the webcomponent has been created)
#Override
public void reload(ResourceConfig configuration) {
try {
new WebComponent(new WebServletConfig(this), configuration);
} catch (ServletException e) {
LOGGER.log(Level.SEVERE, "Reload failed", e);
List<ResourceModelIssue> resources = Collections.emptyList();
throw new ModelValidationException(e.getMessage(), resources);
}
super.reload(configuration);
}
Is there another way to hot-undeploy resources? Is there a way to reset the ServletContainer after a failed reload?
I don't think this can be achieved without the use of a servlet container that supports hot deployments. In my experience, a good way of doing this is using a container that supports OSGi. You can take a look at Eclipse Virgo or Apache Karaf.
For example, in an OSGi environment, you can create modules (called bundles) that can be dropped to a scanned folder to enable features at runtime, or removed from a folder, to disable some features. This is similar to how plugins work in Eclipse IDE, where a new plugin install/uninstall doesn't necessarily require a restart.
Jersey is not technically a servlet container, it is a REST/JaxB framework running on a servlet container.
Most embeddable servlet containers, Tomcat, Jetty, Grizzly allows you to redeploy application and servlets at runtime. But redeployment is typically not a feature you use when you embed the container in code.
Hot redeployment is most useful in production, allowing you to continuously deploy new versions.
On Tomcat you can have new and old version of an application deployed on the same server, and tomcat ensures that new sessions are started on the newest version on the application, but older versions will continue to use the application version they were started with. When an application is no loger used it is automatically undeployed.
Is there a simple, programmatic way to quickly "deploy" and run a standard Java WAR file for local testing without having to install and configure external software packages like Tomcat or Jetty? Ideally something like Jetty's embeddable features but specifically for WAR files.
Java 6 provides the convenient Endpoint class which makes it easy to quickly deploy and test web services, is there something similar for WAR files? For example:
AppServer as = new javax.iwish.AppServer("localhost", 8080);
as.deploy("/", new File("path/to/my.war");
as.start();
I asked too soon, it looks like Jetty does exactly what I need:
Server server = new Server(8080);
server.setHandler(new WebAppContext("foo.war", "/"));
server.start();
Remarkably close to my dreamed up API =D
In development I use jetty as the servlet container. I have the following development configuration:
master project which has wabapp directory
derived project which overrides some of the files in webapp directory
The master project webapp can be started in development mode thanks to providing appropriate WebAppContext to jetty.
Now I want to start derived project analogously, assuming that when request is made, there is an attempt to:
get resource from webapp directory of derived project
if it does not exists, get it from webapp directory of master project
I know that it is possible to override WebAppContext#getResource() method, however some libraries we use in the project seem to perform IO operations on wabapp directory on their own. For example by calling ServletContext#getRealPath("/"), and then reading files without use of ServletContext#getResource() method. The problem could be solved on lower level by some virtual file system on top of File, however it does not seem to be supported in JDK 1.6, any suggestions?
It seems that using something like ResourceCollection is sufficient:
http://download.eclipse.org/jetty/stable-7/apidocs/org/eclipse/jetty/util/resource/ResourceCollection.html
Unfortunately the GWT's DevMode which I use is based on jetty 6, where ResourceCollection is unavailable. I extended the Resource class myself, and together with own GWT JettyLauncher, and thanks to small trick with setting resourceBase on DefaultServlet via reflection, I was able to serve webapp from two directories simultaneously.
protected void doStart() throws Exception {
setClassLoader(new LauncherWebAppClassLoader());
super.doStart();
ServletHolder holder = getServletHandler().getServlet("default");
Servlet servlet = holder.getServlet();
Field field = servlet.getClass().getDeclaredField("_resourceBase");
field.setAccessible(true);
field.set(servlet, combinedResourceBase);
}