Spring MVC Plugin Architecture - java

I am a novice with JavaEE but have some experience with ASP.NET MVC. With ASP.NET MVC, I know we can make a plugin architecture with ASP.NET MVC web app so you can make a dll with MVC structure and put it into the existing ASP.NET MVC web app to make it work without compiling the web app. http://www.wynia.org/wordpress/2008/12/05/aspnet-mvc-plugins/
I wonder if this kind of architecture is possible with Spring MVC. For example, when I make a jar (or war) file with MVC structure and put it into existing Spring MVC web app, it should work without recompiling the web app. If this is possible, how can I achieve that? Any reference would be appreciated.

It is possible without recompiling, but probably not without restarting. You could create a .jar which you drop into the WEB-INF/lib directory. By using classpath scanning you should be able to deploy your new controllers on start-up. You can skip the view entirely and directly output data to the ServletResponse. Rendering a view from a jar may or may not be possible, I don't know.

Sounds like you want to search for "hotdeploy".
What you are asking for is not a feature of Spring, but rather a feature of JVM and the application server. The application server is able to see that indeed your classes have changed and using some clever ClassLoader trickery it can load new versions to the runinng JVM as they become available. Java was not actually designed to work like this so there are some issues (ClassLoader, memory leak, hotdeploy are good keywords for finding more about the potential problems and possible solutions). I would not recommend this for production use but it can be handy during development.
Since this is a feature of the application servers, the actual details depend on the particular application server and are explained in it's documentation.
If you simply want some plugin-magic, not actual hotdeploy, there are other things you could do. A custom ClassLoader can load classes from whatever source (file, network, database..) you want and then you can instantiate and use these with reflection. (This is what happens when you deploy the war to Tomcat/JBoss or whatever). Accessing and dynamically reloading non-class resources inside jar/war files is way easier.

Related

Doing r.js minification with webjars

Our team is writing a server-client application where the frontend is an Angular.js single page application which uses a Spring MVC java backend. The backend serves the application files and the REST endpoints used by the browser end. We are using Maven as the main build system for the application.
We like to take advantage of require.js and r.js to minify the app at the end, and we are also using client side dependency management. Currently we are using bower to download Javascript libraries required but it doesn't feel right to me to download client dependencies to src/main/webapp since this is a source folder. However in order to avoid rebuilding the whole frontend module each time something changes in the client files, this seems the only sensible way to us. This way we can start a web server and it will automatically pick up changes without restart, but as i said this doesn't fit Maven's folder layout.
I'm experimenting with Webjars which seems a better choice in our Maven oriented build and dependency management. Because in Servlet 3.0 containers webjar resources are provided automatically on the server container path it's very easy to use and manage them. It's also possible to create a require.js config to refer to libraries contained in webjars since they are on the webserver path the same way if they were static files, the serving is being done transparently in the client applications point of view.
My only problem is that i don't know how could we achieve r.js minification with this layout, since the source files are in jar files r.js cannot access them. Also the require.js config refers to the runtime server paths which are simply not there in build time.
I see that webjars now have some integration with Require.js + Play Framework but we are not using Play just simple Spring MVC in our case. I really hope there is a way to handle this case because i like the Webjar way of client dependency handling.
You need an asset compiler / pipeline in your build process. There are probably many options but the one I know of is wro4j: http://alexo.github.io/wro4j/

How can one deploy common JavaScript and images to two different EARs while not having to maintain two versions of each file

I have a Struts web app deployed to an EAR that has some pretty extensive JavaScript. I now need to create a new web app that will be deployed to a new EAR but will probably need to share most if not all of the JavaScript and some images from the first application. What's the best way to avoid code duplication so I don't have to put a copy of each JavaScript file in each EAR in my development environment?
You could maintain the Javascript in a separate .jar library and serve it as a resource, not as a static file. That way the JS content would be a regular dependency in your project setup. Unfortunately there isn't a straightforward universal way to do this because you need at the very least a servlet that will send the file from the .jar. (Depending on your web framework you might already have this available.)
This also has some performance implications, but for a line of business application you probably don't need to optimize the load time of your internal Javascripts all that heavily.
Another alternative would be doing this at the source control level, using something like Git submodules.

Custom classloader, JSP execution and resource retrieval inside webapp

Due project requirements, I need to create a webapp that, when executing, will allow some users to upload zip files which are like small apps and will contain .class files, resources (images, css, js, ...) and even lib files. That zip file is almost like a war file.
Any way to code it easily? AFAIK I think I know how to code the custom ClassLoader to load classes from inside the zip file ( Java - Custom ClassLoader - trying to load a class using class file full path ) and even code the resource retrieval when requested by the browser but no idea of how to execute JSP files which will be inside the zip file or load the jar lib files inside the zip file.
EDIT: the webapp must manage applications loaded, there is no way to implement this as answered below because the webapps need the "master" webapp to live. Also that "master" webapp allows versioning of applications. The user will be able to upload a new version and upgrade to it and even do a downgrade if the new version starts to fail.
There is no easy way to do this. It's a lot of work. Classloaders are very finicky beasts. Arguably the bulk of the work of creating something like Tomcat is wrangling the class loaders, the rest is just configuration. And even after all these years, we still have problems.
Tomcat, for example, is very aggressive on how it tries to unload existing webapps, using internal information of the Java class libraries to try and hunt down places for class loader leaks, etc. And despite their efforts, there's still problems.
The latest version of Glassfish has (or will have) the ability to version application deployments. You might have good luck simply hacking on Tomcats internal routing and mapping code to manage versioning.
If you're running an EJB container, you could put your core services in the EJBs and let the WARs talk to them (you could do this with web services in a generic servlet container, but many EJB containers can convert Remote semantics in to Local semantics for calls in to the same container).
You can also look at OSGI. That's another real pain to manage, but it might have enough granularity to even give you versioning, but none of your users will want to use it. Did I mention it's a real pain to manage? We do this for dynamic loading of web content and logic, but we don't version this.
If you must have everything under control of a single WAR, then your best bet is to punt on Java and instead use a scripting language. You tend to have a bit more control over the runtime of scripting environment, particularly if you DON'T let them access arbitrary Java classes.
With this you can upload whatever payload you want, handle all of the dispatch yourself to static resources and logic (which means you get to handle the versioning aspect). Use something like Velocity for your "JSP" pages, and then use Javascript or whatever for logic.
The versioned environment can be pain to pull off. If you don't care about doing it atomically, it's obviously easier. If you can afford "down time" (bring v1 offline then bring up v2), it's a lot easier. If you're uploading the full contents of each version, it's really easy. My system allowed incremental changes and had copy-on-write semantics, so it was a lot harder. But I didn't really want to upload several Gb of media for each version.
The basic takeaway is that when dealing with Classloaders, there be dragons -- nothing is easy with those and there are alternatives that actually get code in to production rather than creating scars and pissed off dragons. Using a scripting language simplifies that immensely. All the rest is dispatch, and that can be done with a filter or servlet.
You WILL get the great joy of reimplementing a solid chunk of the HTTP protocol doing this, that's always a treat as well since the servlet container doesn't really expose that functionality to you. That is, you'll want to do that if you want to be a good citizen on the web. You could always just continually shove content down the clients throat, caching and proxies be damned.
You could manually create a WAR-like structures inside your web container webapps directory and put classes, JARs and JSPs there.
Given that hot redeployment is enabled in your web container it would automatically designate a separate classloader to this new web application that it finds.
In most cases web containers consider any folder having a WEB-INF subfolder containing a valid web.xml file to be a web application. You can restrict access to this new webapp by modifying its context configuration, located in META-INF/context.xml in case of Tomcat.
Controlling hot redeployment, classloader policies etc is dependent on the type of your web container, but I hope your is not worse than Tomcat which could handle all of that.

Tomcat parent webapp shared by configurable children webapps

Currently, we support many clients using the same web app, but each client has a different configuration for accessing their database, setting files etc. As the client list grows, updating the web apps is becoming increasingly arduous, and the duplication of resources is a waste of memory, file space, etc..
What we'd like to do is have a parent web app which is shared by all children web apps. Then have each child web app carry only files specific to them. When the child web app starts up, Tomcat loads the web app from the parent web app and then overrides any files defined in the child web app following an identical package structure.
We've been googling around and haven't found a ready or complete solution. Solutions we've looked at:
Tomcat common/share - could handle class and JAR files, but we don't see a way to handle static and JSP resources residing above the WEB-INF dir.
CATALINA_BASE appears to be more suited for running multiple instances of Tomcat which we'd rather avoid
A Maven possible solution, but we are not big fans of Maven, so would rather avoid it also.
Anybody have suggestions or ideas on how to solve this? If Tomcat configuration is not possible, what about a different application server (such as Glassfish) or a tool for doing dynamic file updated (such as OSGi, rsync). Would like to remove the resource duplication if possible.
Thank you.
There is no such thing as "parent" or "child" webapps. It's not part of J2EE spec and AFAIK it's not supported by any application server.
That said, your problem is twofold:
1) Having shared resources. This part is pretty easy assuming "resources" means static resources (images / CSS / javascript / etc...).
If they are truly shared (e.g. you don't need to have a separate version in some of your webapps), host them elsewhere (separate "common" webapp or put Apache in front of your Tomcat and host them there.
If you do need to have "local" versions of some of those resources you may be able to do some clever conditional URL rewriting or simply write a servlet that would check whether particular resource exists locally and, if not, take it from "common" location.
Precompile your JSPs so you only have to deal with JARs.
If your Tomcat instance only hosts your apps, you can indeed put your JARs in shared (or lib in the latest version); otherwise you can deploy them with each application .
2) Simplifying deployment. I'm not really sure what the big problem is here... It's rather trivial to write an Ant (batch, shell, what have you) script that would assemble and deploy WARs based on "common" and "per-app" directory structures.
Alternatively, you may want to take a look at using JNDI to severely reduce the number of files that have to be deployed (in theory, to a single context.xml for each application).
You can build parent-child hierarchy if you use Spring at your web-apps - Using a shared parent application context in a multi-war Spring application.
I.e. you can define all shared stuff at the 'parent' context and have 'child' contexts just to use it.
If all you had was setting file and configuration changes you could manage these through the context.xml and then you can point the docBase of each application context at a common directory for all the applications to share the same source.
the drawback to this is changes to the application will require a tomcat restart.
This does not however solve your problem if you want to override logic.
A option that I am exploring for a similar scenario is to move the client custom portion into ajax widgets / gadgets. Then have it be part of the configuration files to tell the application which version of the gadget to pull for which client.
you can review documentation for having applications share a docbase here http://tomcat.apache.org/tomcat-5.5-doc/config/context.html

Is it possible to include/embed one Java EE application(war file) inside another?

I have an application which is a portal application and I want to allow other users add their applications to it. In order to do this I need some way to be able to access their applications in mine. Is this possible?
You cannot put WARs inside of other WARs. You need an EAR file to contain WARs, EJBs, etc. One way to implement inter-WAR communication is to package that logic directly in the EAR. It all depends on what you're trying to do.
the way to do inter .WAR communication is by the method
http://java.sun.com/j2ee/1.4/docs/api/javax/servlet/ServletContext.html#getContext(java.lang.String)
ServletContext.getContext(URIOfOtherWAR_resource)
I've used this succesfully for doing what you're talking about.
Maybe you need a plugin system or portlet, so your user will not develop a war application but include their portlet inside your application (war). There's a standard : JSR 168 and several implementations :
http://developers.sun.com/portalserver/reference/techart/jsr168/
As others have pointed out, embedding WARs inside WARs is not an option. However, I may have a workaround for you.
Most Web containers I'm familiar with have a "test deployment / auto deploy" mode / capability, where they will automatically deploy an application if the WAR is copied into the right directory.
Your portal application could certainly allow uploading WARs, and it could store the uploaded bytes in a given directory under a given file name. Your Web container could do the rest. You could then link to the new application from your portal, or whatever. All this is relatively easy to do.
However, be advised that this is a horrible idea if there is any security concern whatsoever. You are essentially allowing your users to execute arbitrary code on your server. Unless you completely trust all potential users to be both non-malicious and perfectly competent (think infinite loops), you are asking for a lot of trouble here.

Categories

Resources