I'm writing a very simple web framework using Java servlets for learning purposes. I've done this before in PHP, and it worked by consulting the request URI, then instantiating the appropriate class and method.
This worked fine in PHP, as one can do something like $c = new $x; $x->$y;. I'm unsure however of how to translate this to Java, or even if this is an appropriate way to go about it.
So far, I've tried:
Router router = new Router(request.getPathInfo());
String className = router.route(); //returns com.example.controller.Foo
Class c = Class.forName(className);
Object x = c.newInstance();
Foo y = (Foo) x;
y.doSomething();
This seems fine for a couple of routes, but doesn't seem like it would scale well, nor would it allow for sourcing routes from a configuration file.
How should I make it work?
Get hold of actions in a Map<String, Action> where the String key represents less or more a combination of request method and request pathinfo. I've posted similar answer before here: Java Front Controller
You can fill such a map either statically (hardcoding all actions) or dynamically (convention over configuration, looking up classes in a certain package, or scanning the entire classpath for classes with a certain annotation or implementing a certain interface).
And just stick to Servlet. The Filter isn't there for. At highest use it to forward the request to the controller Servlet. In the Servlet, just implement HttpServlet#service().
I would use a Servlet Filter as Front Controller. The router would connect paths with request dispatchers. In the doFilter method you would convert ServletRequest to HttpServletRequest, extract the request path and match it against the registered mappings. The result of this mapping is a request dispatcher you would dispatch the request with.
In pseudo code:
doFilter(ServletRequest request, ServletResponse response) {
httpServletRequest = (HttpServletRequest) request;
path = httpServletRequest.getRequestURI();
dispatcher = router.getTarget(path);
dispatcher.dispatch(request, response);
}
Depending on your need the default routing mechanism of the Servlet API could be sufficient.
Not quite sure what you're after but you might want to take a look at Java servlets. Granted many web frameworks are abstracted above plain servlets, but it's a jolly good place to start learning about Java web apps if you ask me (which indirectly you did ;) )
Download the Java servlet specification here: Java Servlet Spec - it's quite interesting.
How should you make it work? However you want it to. If you're just doing it for learning purposes, whatever you do will be fine.
I would suggest having all your actions implement the same interface though (maybe extend Servlet) so that you don't have to compile in all different classes.
Then you can essentially do what you're doing, except that your cast to Foo becomes a cast to Servlet and then you don't have to have a special case for all your different classes.
You can then also load up the routes from configuration (maybe an XML file).
Essentially what you're doing is implemented by the Struts 1 framework so it might be worthwhile reading up on that (it's open-source so you can also look at the source if you want).
Related
In a Spring MVC application we have a Controller that would execute before calling the JSP. The Controller would prefetch some values from the database and set them in the model and forward the control to JSP.
How do I implement this feature in CQ 5? I want the SlingFilter to execute before the JSP is executed. And the JSP is not a page component but a component that appears in the side kick.
Note:
I can do this by writing my own SlingSerlvet that would prefetch my required values and use the RequestDispatcher to forward to the JSP.
But by this method I would have to go through a URL like "/bin/.*". And this is again at a page level I want this kind of functionality at component level.
So to answer your specific question, if you want a filter to be executed before a component is called you would create a filter that is listening to Component level filter scope.
See
http://sling.apache.org/documentation/the-sling-engine/filters.html
You would then have your filter change the incoming request to a SlingServletRequest and determine if the target resource is the one that you are looking for.
However this filter would be executed on every single component that is being included on a page. The reverse process of this that may be useful to you is the ResourceDecorator.
http://sling.apache.org/documentation/the-sling-engine/wrap-or-decorate-resources.html
These are executed when the resource is identified, prior to the servlet and filter calls, which would allow you to verify if a resource is a type that you are interested in, and then allows you to add additional information to the resource object.However this is, once again a service that would be applied to every resource that is identified.
However, if what you are looking for is a filter that is only executed for a specific path, then no. Sling doesn't do that. You mentioned Spring MVC and Spring MVC works on a completely different concept of MVC then what Slings version of MVC does.
EDIT
So in a traditional web app, the servlet would be at a fixed position and all filters are applied prior to the call to that servlet. In Sling you are dynamically wiring servlets together to generate the resulting page. So each time that you are in a servlet and call directly or indirectly the request dispatcher, it's executing the resolution process again and applying a series of filters again before the new servlet is executed.
To prevent a high level filter that needs to applied only to the main request being applied on every single internal dispatch, they came up with the idea of contexts, or chains of filters that are applied at different times and associated with different types of includes.
Here is a basic filter that will log a message when it's called. I did this from memory so you'll need to dink with it.
#SlingFilter(scope = SlingFilterScope.COMPONENT, order = Integer.MIN_VALUE)
public class SampleFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(SampleFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SlingHttpServletRequest slingRequest = (SlingHttpServletRequest) request;
Resource res = slingRequest.getResource();
if (!(res == null || ResourceUtil.isNonExistingResource(res))) {
LOG.error("this servlet is called before resource {} at path {}", res.getName(),res.getPath());
}
chain.doFilter(request, response);
}
}
The important part of this is scope = SlingFilterScope.COMPONENT take a look at the page I had listed earlier and try out different combinations of slignfilterscope and you'll see how it's being applied at different times. scope = SlingFilterScope.REQUEST would be once at a top level on a per page basis.
JE Bailey's answer is correct as far as Filters are concerned, but I suspect your problem might be solved in a different way that better fits Sling's view of the world.
Sling promotes the use of OSGi services for business logic, and scripts should be a thin layer above that. Moving your logic to OSGi services and calling those from your scripts is the recommended way.
You might also have a look at Sling Models which can include processing steps (with #PostConstruct) before the rendering scripts kick in.
But by this method I would have to go through a URL like "/bin/.*".
You can also register a servlet against a resource type, as well as by path, e.g. (from the Sling documentation):
#SlingServlet(
resourceTypes = "sling/servlet/default",
selectors = "hello",
extensions = "html",
methods = "GET")
public class MyServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
...
}
}
If you remove the "selectors", "extensions" and "methods" parameters on the annotation, this servlet would bind against all calls to sling/servlet/default without requiring binding against a set path.
I'm running some Scala code (with Java socialAuth library) that requires an HTTPServletRequest to be passed in as a param.
def myClass(prov: String, site: String, request: HttpServletRequest): {
//some initial code here
val session = request.getSession()
session.setAttribute(/*some params*/)
//code continues...
}
So the HttpServletRequest seems like a really cool way of storing session variables and passing a session between methods. However, I'm not quite sure how to test this code, as I don't really understand what the HttpServletRequest interface is.
I've done a bit of research, but I was wondering if anyone could clarify for me. HttpServletRequest is an interface, which means it can't be instantiated on its own. How, then is it used in code?
EDIT: as in, when a method takes an HttpServletRequest as a parameter, what implementing class is usually passed in?
FOLLOWUP: Based on the answers given, HttpServletRequest is implemented differently by different servers; Ireeder pointed out, for example, that Apache even has multiple implementations. How, then, does code specify that the server needs to use its implementation? In other words, lets say I have test code that uses myClass:
def otherClass(){
val site = "www.example.com"
val provider = "twitter"
val mockRequest = mock(HttpServletRequest.class) //using https://code.google.com/p/mockito/. (eclipse throws error..not too sure about syntax but throwing up this example quickly, so will edit later)
myClass(provider, site, mockRequest)
}
I assume this is OK for testing, as Mockito creates a mock object, but when otherClass() needs to be implemented on a server, how is its code adjusted? (Sorry, I'm a bit new at this, so bear with me...) If val mockRequest needs to be implemented with whatever HttpServletRequest implementation is used by the server (Apache, Oracle, etc), how does the user specify this in otherClass? Will something like this change:
//deleted line: --val mockRequest = mock(HttpServletRequest.class)
//changed line: myClass(provider, site, mockRequest) to below:
myClass(provider, site, javax.servlet.http.HttpServletRequest)
be interpreted and implemented correctly by the server?
Container implementers like Oracle or Apache extend the HttpServletRequest interface with their own implementations that actually do something. You could do the same for your testing, or use something like Mockito to mock it.
The only time you should be providing an implementation of an HttpServletRequest is at unit testing time, not when your code is running in a servlet container. The container will pass you its own HttpServletRequest, and your code should not care about the exact implementation of that interface. It should only use the methods provided by the HttpServletRequest interface so that it is independent of the container it is running in.
If you need to test the behavior of your code when it's running in servlet container, you can do manual testing, or use a testing framework that makes HTTP requests, like HttpUnit
Spring users can use the class MockHttpServletRequest (JavaDoc)
I want to write a servlet or filter that automatically maps the url /xxx/yyy/zzz to class XxxYyyZzz.java.
For example the following URLs will map to the following java classes:
/comment/add --> CommentAdd.java
/comment/delete --> CommentDelete.java
/comment/view --> CommentView.java
/search --> Search.java
/viewposts --> Viewposts.java
In addition the servlet or filter must comply with two extra requirements:
The servlet or filter should have a servlet mapping of "/*", I dont want a prefix with several servlets "/comment/*", "/search", etc.
Maybe difficult, but having a servlet mapping of /* should not allow it to override the JSP processing. Meaning, if a class is not found, it should check if a jsp page exists and run it.
I want to know how can this be done using the Servlet API. Please don't refer me to any framework that does the job. Just show me the code.
The classes that are mapped to will follow the command pattern or could be a subclass of the HttpServlet. In both cases, a method should exist like "execute(HttpServletRequest request, and HttpServletResponse response)". This method will be automatically executed once the URL is accessed and the java class is figured out possibly using a single servlet or filter.
I'm not sure, if I got what you mean. In case I did:
You need nothing special, write a single Servlet mapped to "/", so it gets everything. Parse the PATH_INFO (don't know now how it gets called in Java), use Class.forName (or use a pre-filled Map), and call its method execute.
Here is a http://www.tuckey.org/urlrewrite/ filter implementation that might help you. Check it out. I have not used it myself though.
You can use Stripes framework with its default NameBasedActionResolver config.
I always wondered why there exists no removeParameters() method in Servlet API.
What could be the motive behind this design?
Here is a scenario: I am posed with a challenge in a proprietary MVC framework that I am compelled to use. This framework uses a Controller Servlet that hosts an algorithm in it's post method:
doPost() {
//create instance of action - just like struts action
action.init
action.preexecution
if(redirection state is not set)
action.process
action.postprocess
action.finish
}
The only way I can skip process of any particular action would be by setting a redirection url. The Controller Servlet is FINAL. Now, when I do a requestdispatcher.forward from say the preexecution method of an action, the controller will go ahead and execute the rest of the methods and not skip the rest. I cannot change this behavior, neither can I set the redirect, coz I need to do a forward. It works fine as long as I am not forwarding request to the same action. When a request is forwarded to the same action, the http parameters are all the same. This would take it into a never ending loop. Hence, I am compelled to add extra parameters indicating that it is a repeat request and should be treated differently.
Not sure if my problem made sense, but thought this is a good forum to post the same.
Umm... because it would serve no purpose? Request parameters are sent by the client to the server. The server is free to ignore them, but what practical effect would you expect such a removeParameter() method to have?
Edit: Request parameters are meant for the communication between server and client. For server-internal communication, you can use request attributes, which can be set and removed.
EDIT: McDowell reminded me of HttpServletRequestWrapper, so I'm changing the below to make it a little less work... Thanks McD!
You can decorate the request to "hide" parameters you don't want and/or add extra parameters.
Something like (off the top of me head -- no compiling so the API might be a tweak off...)
public class MyParameterHider extends HttpServletRequestWrapper {
public MyParameterHider(HttpServletRequest request) {
super(request);
}
public String getParameter(String name) {
if ("parameterToHide".equals(name))
return null;
return realRequest.getParameter(name);
}
// similar for getParameterNames and getParameterMap - don't include the hidden parm
// all other methods are strictly pass-through and are automatically
// handled by HttpServletRequestWrapper
}
In your forward, just wrap the request in a ParameterHider when calling doFilter:
dispatcher.forward(new MyParameterHider(request), response);
Patterns FTW!
Hope this helps!
For the last couple of years I've had my head in Python, where there are numerous choices for simple, minimal frameworks that allow me to stand up a website or service easily (eg. web.py). I'm looking for something similar in Java.
What is the simplest, least-moving-parts way of standing up simple services using Java these days? I'm looking for something as simple as:
the ability to receive HTTP requests
the ability to dispatch those requests to handlers (preferably a regular expression based url to handler mapping facility)
the ability to set HTTP headers and generally fully control the request/response
Bonus points if the framework plays well with Jython.
[Update] Thanks for the responses, some of these look quite interesting. I'm not seeing the url dispatch capability in these, however. I'm looking for something similar to Django's url.py system, which looks like:
urlpatterns = patterns('',
(r'^articles/2003/$', 'news.views.special_case_2003'),
(r'^articles/(\d{4})/$', 'news.views.year_archive'),
(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)
Where you specify a url regular expression along with the handler that handles it.
I liked to worth the Simple HTTP Server from the Simple Framework. It offers a nice Tutorial about how to start as well.
there are several alternatives:
servlets
restlet: lightweight REST framework
jax-rs: using jersey or the restlet module implementing the jax-rs specs
grizzly: NIO based server (with HTTP support + handlers)
apache mina: event-driven, async server (with HTTP support)
all these frameworks come with a built-in server.
EDIT
jax-rs has a similar approach using url templates:
#Path("/users/{username}")
public class UserResource {
#GET
#Produces("text/xml")
public String getUser(#PathParam("username") String userName) {
}
}
then put your handlers in an Application object:
public class MyApplicaton extends Application {
public Set<Class> getClasses() {
Set<Class> s = new HashSet<Class>();
s.add(UserResource.class);
return s;
}
}
another example with JAX-RS:
#GET
#Produces("application/json")
#Path("/network/{id: [0-9]+}/{nid}")
public User getUserByNID(#PathParam("id") int id, #PathParam("nid") String nid) {
}
EDIT 2
Restlet supports a centralized configurations like Django, in your Application object:
// Attach the handlers to the root router
router.attach("/users/{user}", account);
router.attach("/users/{user}/orders", orders);
router.attach("/users/{user}/orders/{order}", order);
Servlets might be the way to go. To do very simple things you only need to override one method of one class. More complicated stuff is of course possible, but you can go a long way with a little work.
Investigate Tomcat or Jetty - both are open source and well supported.
public class HelloWorldServlet extends HttpServlet {
public void doGet( HttpServletRequest request, HttpServletResponse response )
throws ServletException, IOException
{
response.setContentType( "text/plain" );
PrintWriter out = response.getWriter();
out.print( "hello world!" );
}
}
Note: This is more general discussion than answer.
I'm having similar issues coming from Python for 10+ years and diving, as it were, back into Java. I think one thing I'm learning is that the "simplicity" factor of Python is very different from that of Java. Where Python abounds with high-level framework-- things like web.py, Java seems much more lower level. Over the past few months, I've gone from saying "What's the Java way to do this easy in Python thing" to "How does one build up this thing in Java." Subtle, but seems to bring my thoughts around from a Python-centric view to a more Java-centric one.
Having done that, I've realized that standing up a website or service is not simple for a Java outsider, that's because there's a large amount of info I have to (re)grok. It's not as simple as python. You still need a webserver, you need to build a "container" to drop your Java code into, and then you need the Java code (am I wrong on this, everyone? Is there a simpler way?).
For me, working with Scala and Lift has helped- and not even those, but this one thread by David Pollack. This was what I needed to build a Jetty server. Take that, follow the directions (somewhat vague, but might be good enough for you) and then you have a servlet container ready to accept incoming traffic on a port (or 3 ports, in his case). Then you can write some Java code using HTTPServlet or something to go the rest of the way.
Again, this is just what I did to get past that barrier, but I'm still not a Java guru. Good luck.
I've hard about: Apache Mina
But quite frankly I don't even know if it is what you need.
:-/
:)
Jetty is a pretty nice embedded http server - even if it isn't possible to do the mapping like you describe, it should be pretty easy to implement what you are going for.