I do have a Java web application which has several servlets, I want to turn it into an optional module of a Spring mvc application. Ideally I would like to add the module as a "dependency" to make it available and add the proper link in my primary UI.
Is there a popular way to achieve this?
Many thanks in advance!
Convert all projects to maven projects, then Servlet specific projects are modules specified in the overarching MVC parent project.
That way, at build time, all required Servlet projects are automatically built by maven whenever you build the parent... And you can optionally exclude Servlets at build time.
To convert a normal java servlet project to spring mvc you would need to do the following
1) In your web.xml you would have to specify your dispatcher servlet with and the url pattern for which it would get invoked. Specify the servlet class as the dispatcher servlet class and servlet name as a custom name for this servlet
2) Create an xml file as servletname-servlet.xml
3) Convert your custom servlets to controllers by having them implement the Controller interface and specify then in the xml file created in the second step
4) Define the mapping of these controllers to the requests
5) Define a view resolver for the requests
6) Deploy
These are broadly the steps you would need to perform to convert your servlet project to Spring MVC
Depending on your servlet container(*), you could try to put the small application in its own servlet context on same container: that means that it would be a totally independant web application.
Then you install in main application a special controller mapped to a full hierarchy that would act as a forwarding relay for the secondary application. Something like :
#Autowired
String extContext;
#RequestMapping("/optapt/app1/**")
public void relay(HttpServletRequest req, HttpServletResponse resp) {
ServletContext ext = req.getServletContex().getContext(extContext);
String extUrl = req.getServletPath();
if (req.getPathInfo() != null) {
extUrl += req.getPathInfo();
}
ext.getDispatcher(extUrl).forward(req, resp);
}
That way, provided you have a global proxy that fordibs external clients to access the second application, all security can be managed by the main, and the second will only receive forwarded request from the main.
If for any reason, you have no proxy to hide the servlet container, you will still (but only) have security by obfuscation, since the direct addresses to the secondary application will never be published, provided you consistently only write addresses relative to first application in links and form actions
(*) ServletContext.getContext() may return null for security reasons on some servlet containers.
Related
I'm investigating a Spring Boot project generated by JHipster and found out that its request mappings aren't done via web.xml nor via Spring's #RequestMapping but like so:
ServletRegistration.Dynamic someServlet =
servletContext.addServlet("someServlet", new SomeServlet());
someServlet.addMapping("/someUrl");
someServlet.setAsyncSupported(true);
My questions are:
Are there any reasonable advantages of dynamic registration instead of classic mapping?
Is it spring-boot's standard of registering mappings or it's just a will of jhipster's owner?
Is someServlet.setAsyncSupported(true) just another way of making response.setHeader("Access-Control-Allow-Origin", "*")?
Is there any reasonable advantages of dynamic registration instead of classic mapping?
Dynamic servlet registration Servlet 3+ way of registering servlets. In Servlets 3 you can avoid creating web.xml and configure application in pure Java. It gives you some advantages like compile time check if everything is fine there and what's more important since you do it in Java code, you can do some additional checks or conditions - for example register particular servlet only if environment property is set or class is available on the classpath.
It's not a replacement for #RequestMapping. In case of Spring Boot you will use it most probably when you want to register some 3rd party servlet - like Dropwizard Metrics servlet in case of JHipster.
Is it spring-boot's standard of registering mappings or it's just a will of jhipster's owner?
There are at least 2 ways of registering additional servlets in Spring Boot. See answers here: How can I register a secondary servlet with Spring Boot?.
Your own controllers you map as usual with #RequestMapping.
Is someServlet.setAsyncSupported(true) just another way of making response.setHeader("Access-Control-Allow-Origin", "*")?
Nope. For setting this header you use usually CORSFilter (read more: Enabling Cross Origin Requests for a RESTful Web Service). asyncSupported flag is used to make servlet able to process request asynchronously.
I've built an application that loads multiple plugins over SPI. Each plugin has to implement the FrameworkPlugin interface.
public interface FrameworkPlugin {
...
ContextHandler getWebContent();
String getPluginID();
...
}
An example implementation would be
...
ContextHandler getWebContent() {
WebAppContext wac=new WebAppContext();
wac.setBaseResource(new ResourceCollection(new String[] {"./src/main/webapp"}));
return wac;
}
...
The Main-Project runs a single Jetty instance, which should be used by all plugins providing web-based services. A plugin has to be able to configure it's individual environment within its own context, except the base URL, which is managed by the main project.
...
for (FrameworkPlugin p : PLUGINS) {
ContextHandler h= p.getWebContent();
h.setContextPath("/plugin/"+p.getPluginID().toString());
collection.addHandler(h);
}
jettyInstance.setHandler(collection);
...
So in theory, plugins should be accessible under /plugin/<id>. Unfortunately Jetty throws an IllegalArgumentException, because plugins set ./src/main/webapp as resource base, which does not exist in the main project.
So how to supply a context handler via the plugin interface?
Deploying WARs is not an option, as the loading mechanism can't be changed. Everything has to be done by using the plugin interface.
If this isn't going to be a WAR based project, then skip the use of WebAppContext entirely, and just use the Handler system in Jetty itself.
The WebAppContext is a specialized Handler meant to be used with a full blown and complete Web Application that follows the servlet spec. It mandates behavior that is mandated by the servlet spec, from the mundane (how url mapping order behaves), past the black art (per element descriptor order lookup and override), to the complex (webapp classloader isolation).
The Handler system in Jetty can be 1..n Handlers, in a Tree (via HandlerCollections), sometimes with Context, mutable Handler collections, and all exists at the same classloader as the server (if you want it to). Feel free to url map with regex, or your own implementation of level 3 URI templates. Completely up to you what you want to do with it. You have many pre-built Handlers and base Handler to build up from.
You'll still have access to the standard HttpServletRequest and HttpServletResponse, along with the async processing and I/O that those provide. But you'll also have access to the raw internal Request object which offers even more features over the HttpServletRequest.
Incidentally, many servlet based applications support plugins now. Most accomplish this using Controller Servlets, or Filters, or manipulation of the ServletContext's registrations.
i wonder if there's a way to enable or disable servlets (or at least mappings for servlets) other than web.xml. I have multiple kinds of servers which use the same web.xml (i can't change this) so this is why another way of enabling/disabling servlets would be useful.
Thanks,
Teo
You could use #WebServlet annotation with servlet 3.0 onwards, not sure if this will work for your requirement, please comment if this isn't the way you want to
#WebServlet("/hello")
public class HelloServlet extends HttpServlet {
// code code code
}
As far as i am aware there is no such thing as programmatic disabling of servlets other that the deployment descriptor.
The way that i would approach such an issue is the following:
-I would add an if statement in each of my servlets service() method that i would like to control access to such as:
if(MyCustomSecurity.isServletAccessible(request)){
//here is your code that you have right now
}else{
//redirect request to an error page maybe
}
-Create this method isServletAccessible() in MyCustomSecurity class that would return a boolean on weather the user is allowed to acceess the servlet or not
If you are using Tomcat 7.x / Servlet 3.0 you can programmatically add a servlet filter to dynamically enable/disable access to some of your servlets without touching your web.xml file nor your application code.
I'd just create a web filter that reads some kind of configuration and passes or redirects on specific, configured paths.
Another option is to block paths on security layer e.g. Spring Security (actually it uses something like described above).
what about creating a Filter (a class that implements javax.servlet.Filter), then in a xml or properties file or even in database, you can add the servlets' names that the user can access or can't access.
Is it possible with Guice (and even in Java in general) to iterate over all classes in a particular package and add them to Guice?
The underlying problem: I'd like to be able to route all traffic to /admin/* to a single servlet which redirects accordingly. Then I'd like to be able to just add servlets to the same package and have them get picked up automatically. E.g. If I navigate to /admin/showCompanyDetails, I'd like that to redirect to a servlet called showCompanyDetails.java in the admin package.
Furthermore, I'd like this to work in such a way that all I have to do to add further admin functions is to drop a new class into the admin package. I.e. No factory methods to update and no containers to add to.
So far, the closest I've come is to have the redirect servlet create a Guice injector with a module that contains all the admin servlets. But as I said, I'd like to avoid having to update a Guice module.
Also, I'd like this to be possible in AppEngine.
And I want a pony.
There are some possibilities:
Use Servlet 3 #WebServlet annotations on your servlet classes, so they get picked up by a Servlet 3 web container. Then you can use Guice to inject dependencies, see here for an example.
Use guice-automatic-injection to bind your servlet classes in your classpath (they must contain their path similar to Servlet 3 via annotations or provide an accessor for it). Then you can create a Guice servlet module which retrieves all those servlets from Guice and registers them as servlets to their provided paths.
Both ways may be usable in AppEngine, but I haven't got experience with it.
Getting a pony is easy if you use just Object as its base class ;p
We've got some Pure Servlets (pure Java classes following the Servlet API, no framework) that we'd like to include in a project that relies heavily on the Spring Framework.
What's the best way of including these servlets in the project, when all the new code we're writing is making heavy use of Spring 3 features?
your servlet container can run multiple servlets, spring is just one of them. why not just include your servlets in the web.xml and see if it works? it should work. spring is not that intrusive, yet (but obviously it already intruded the minds of many developers)
If you declare servlets in the web.xml, alongside the Spring front controller, it most certainly will work.
You just have to be careful when you declare which URLs map to the servlets. If you send "/*" to the Spring front controller, none of your requests will reach your other servlets. Be specific about what you need to send to each one.
As you might know, servlets cannot be configured as Spring beans. If your question is about colloborating with spring beans from a servlet, do refer this thread and also this
Spring provides a couple of classes to make this bridging easier.
ServletForwardingController
Spring Controller implementation that
forwards to a named servlet, i.e. the
"servlet-name" in web.xml rather than
a URL path mapping. A target servlet
doesn't even need a "servlet-mapping"
in web.xml in the first place: A
"servlet" declaration is sufficient.
Useful to invoke an existing servlet
via Spring's dispatching
infrastructure, for example to apply
Spring HandlerInterceptors to its
requests.
ServletWrappingController
Spring Controller implementation that
wraps a servlet instance which it
manages internally. Such a wrapped
servlet is not known outside of this
controller; its entire lifecycle is
covered here (in contrast to
ServletForwardingController).