I want to create a servlet that will allow me to upload image files from the client to the server. I am helping myself with the tutorial i found at apache site:
http://commons.apache.org/fileupload/using.html
On my way i am finding some complications and doubts:
Question 1
I would like my servlet to prepare an object with all the values from the request(included images as byte[]) and pass it to an #EJB that will insert all in the database.
Is that possible? Could you give some pseudo code tips on how to improve my current servlet to do that?
#WebServlet(name="uploadServlet")
public class FileUpload extends HttpServlet {
#EJB
private DBAccessEJB ejb;
private static final long serialVersionUID = -1062753489906645120L;
// Will be triggered when a post method is sent by the user(Example: Form
// submit)
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// Check if the request is multipart
boolean isMultipart = ServletFileUpload.isMultipartContent(req);
// Create the object that willBe passed to the EJB
Thing thing = new Thing();
if (isMultipart) {
// If it is multipart, save the items in a FileItemfactory
FileItemFactory factory = new DiskFileItemFactory();
// Create an upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
try {
// Get the files out of the request
List items = upload.parseRequest(req);
Iterator iterator = items.iterator();
while (iterator.hasNext()) {
// Get each of the items inside the items list
FileItem item = (FileItem) iterator.next();
// If the item does not come from a field
if (!item.isFormField()) {
//transform the uploaded images to byte[]
//setTheImageValues of the object
}
else {
//set the text values of the object
}
}
//Pass the prepared object to the EJB to be inserted in DB
ejb.save(thing)
} catch (FileUploadException fue) {
fue.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Question 2
I thought about passing the request to the servlet through the managaged bean, instead from the JSF page, but i don't really know how to do it. Could you give me some tips? I also don't know how to do it in the normal way, from the page,what do you think would be the best way?
This is what i did so far regarding to the managed bean:
public void save() {
FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest req = (HttpServletRequest)fc.getExternalContext().getRequest();
//What else do i need here to pass the request to the server?
}
This would be at the page inside a multipart form:
<h:commandButton value="Submit" action="myBackingBean.save"/>
Question 3
In my JSF page i have more or less 10 values almost all are Strings. I take them from the JSF and temporary store them in the JSF page. If the servlet could take all the values from the request, there would be no need for this attributes in the backing bean. Do you think is this approach a good thing to do? Will this be process transaction secure, or is there any risk?
Doubt #1 :
It looks like you use the EJB here as a service layer containing a DAO annotated with EJB annotations to make it a session bean. I do not like this approach and you'll run into issues caused by the difference of the EJB world and the HTTP request world.
It is important to note that one of the biggest reasons to use EJB's is to manage transactions and transaction have to remain short, in the order of ms. This is for a number of reasons, like for example locks on the database. However when dealing with http requests with uploads, this is no longer valid.
From another perspective is that a service layer should represent an abstraction of the database model and should show what you can do with the model from a user perspective. The user does not want to save an image to the database, the user wants to add a portrait to his profile.
instead of
ejb.save(thing)
I prefer functions like
profileService.addPortrait(uid, byte[] image);
This explicitely states what it does, and also satisfies the requirement of short transactions. This means the profile entity is available for other requests which may come concurrently (like some status image, or inbox status, ...)
Doubt #2 :
When in Rome, do as the Romans do...
and start by learning some basics of the language. In this case learn JSF from some tutorials.
Doubt #3 :
Intercepting the request parameter in flight between the browser and the JSF component breaks the component architecture and the data hiding principle. It will also bypass any security measures and validation implemented in the server side parts of the JSF components.
If you use the JSF component framework, it makes sense to only ask the values from the components, not from the request itself.
From your 3 doubts I feel you have a bigger doubt : Should I be using JSF?
If it is mandated by your employer : suck it up, and start hitting the books... Learn which problems JSF and EJB's solve and frame your work in terms of those problems.
If you have the freedom to choose : choose a lighter framework, e.g. Spring + Spring MVC. You'll gain experience and encounter those problems at your own pace.
Question 1-
Absolutely you will need Unique Identifiers for your files, but that becomes less complicated if you do things like storing files in folders by date/username, etc...
Here is a basic workflow for your program that you could use, based on what you have shown so far:
Client computer -> FileUploadServlet (utilizing Apache Commons File Upload)
Once inside the FileUploadServlet:
a) Save the information from the request to a Database by way of your EJB including the file name, Mime Type, information, etc...
b) While still inside the servlet, upload the file to your server, or if you need to, use a commercial solution such as Amazon S3 or Google Storage (by way of a Java API such as JetS3t)
Afterwards, return any necessary information to the client.
Question 2 -
What is your reasoning for requesting throught the Bean, why not just make the Servlet the action instead, and collect the information from the request? I would not make the Bean's save method available on the JSF, as that sounds insecure and un-authenticated.
Question 3 -
Same as above, why store information, even if temporarily, when it is available elsewhere?
Related
I have internationalization module and application runs in two different modes. To change the mode, we need to restart the tomcat server. Mode 1 supports two languages and mode 2 supports 5 languages. The languages are stored in a .json file.
Every time the user hits index.html, in the #RequestMapping of this page, I check the application mode. And based on this application mode I read the correct .json file. Extract the list of languages and set that in the model and then I return the page to the client.
Problems with this approach is - every time I hit the index.html file, the application reads the file from disk. which is not only unnecessary but also time consuming and it rings annoying bell to my developer ego.
What I'd like to have instead is, when the application boots up, I know the application mode.
How can get the spring MVC to read the file in the beginning and store this data as long as server is running? Is it even possible?
If yes, can you let me know what parts of Spring MVC do I need to look into?
I read about HandlerInterceptor and #ModelAttribute but it merely states how can I insert the data in each request. However, what I really want to know is how the persist the data read from the file once.
One of the approaches could be tohave a bean, which impements InitializingBean and loads the file in 'afterPropertiesSet' method. It would also have a method to return the list of languages and it could be wired into all other bean which need it.
You could also do it in 'HandlerInterceptor', just have it implement InitializingBean and store the list in the class variable.
e.g.
public MyInterceptor extends HandlerInterceptorAdaptor implements InitializingBean {
private List<String> languageList;
#Override
void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView)
throws Exception {
//set list in the model
}
#Override
public void afterPropetiesSet() {
languageList=...; //read file
}
}
When developing a Web Application in Java, launching in Tomcat, I need to be able to create (dynamically) a new static address (link,URL) in the server that will be used to view the information of a new item, let's call it new_item_001, which have been just created by one user.
Say I want to create a new address
www.domain.com/webapp/items/new_item_001
which can be used to render a view of the contents of new_item_001.
Which is the best approach to do this?
Should I dynamically create a new servlet class for this view?
Should I dynamically create the folder items and one html file new_item_001 for this item inside of it?
Should I edit the server address mapping rules to create this static address and map it to a central servlet which somehow knows which item to display?
I understand the question is ill posed, and that I am far from even understanding the issue, so I would like some guidelines on what to look for.
None of the above.
You should simply have a servlet mapped to /items/*. When a request come to this servlet, analyze the actual path of the request, extract the part after /items/ to know the actual value (new_item_001) in your example, get the data corresponding to this item from the database, and send it to the browser.
Using a true MVC framework like Spring MVC would make that much easier. You could simply map a method of a controller using
#RequestMapping("/items/{itemId}")
public Item getItem(#PathVariable("itemId") String itemId) {
...
}
and let the framework do all the URL parsing for you.
I would like to tackle this in a simple way. Creating a servlet for each created item would be overkill and become quite cumbersome to manage after a successful run of the application for some time.
Changing/editing server mapping URL looks very naive approach and is not scaling too. Let configuration be there and change them only when you actually need to change them.
My suggestion is to create one servlet that handles all these requests. For example, you may save item information on a datastore or on file system(i.e images uploaded by user etc..). Next time a GET request is received by the application to fetch saved information of an item, servlet should be able to reference the item on database associated with the item id on the URL. If you don't wish to expose item id/surrogate key in the database, you can also have a simple mapping between them by implementing your own logic. Frameworks like Spring MVC do a good job in mapping URLs to resources like this should you wish to use a framework.
Additionally to minimize the number of requests to the same item, you can also implement an HTTP caching strategy(i.e. ETAG, If-Modified-Since) by instructing your web server at the time of first GET request from a user.
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 am exploring JSP to implement dynamic web pages. One issue to solve is navigation between pages. Users have the possibility to go back and forward in their browsers.
This has to be handled. If someone logs out (for example), we don't want someone else to retrieve the session or data by clicking 'go back'. Another example is that we don't want to resubmit forms twice.
I am looking for tips and advices to solve page navigation issues. I would like to create a list of issues one has to take care of + possible solutions:
Issues:
Making sure sessions cannot be retrieved/hijacked with go back/forward clicks
Making sure forms and not submitted twice
Making sure users cannot fiddle cookies or URL data or hidden fields to break control flow and security
Solutions:
Implement a stack of visited pages
When a page is invoked, register the moment it is displayed to differentiate new requests from 'go back'
Control current session
P.S.: I have seen this question, but there is no real answer to it.
Making sure sessions cannot be retrieved/hijacked with go back/forward clicks
Just disable browser cache of those pages. See also Prevent user from seeing previously visited secured page after logout.
Making sure forms and not submitted twice
Generate a long, unique and impossible-to-guess string, store it in both the session ..
String token = UUID.randomUUID().toString();
((Set<String>) session.getAttribute("tokens")).add(token);
request.setAttribute("token", token);
request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
.. and as a hidden input field of the form.
<input type="hidden" name="token" value="${token}" />
Upon submit, compare and remove the key in the session. If it was in the session, then proceed with submit.
if (((Set<String>) session.getAttribute("tokens")).remove(request.getParameter("token")) {
// Valid token. Proceed with submit.
} else {
// Invalid token. Possible double submit.
}
Making sure users cannot fiddle cookies or URL data or hidden fields to break control flow and security
Just write robust code yourself or use an existing and robust MVC framework like JSF2, Spring-MVC, Struts2, etc.
Solutions:
Implement a stack of visited pages
When a page is invoked, register the moment it is displayed to differentiate new requests from 'go back'
Control current session
Cumbersome.
To prevent double submission, I will use an example Apache Struts 1 used by using HttpSession.
What Struts did was to generate a random token that is stored in a session and added in a form page in a presentation layer (JSP). When a user submit a form, it checks from the session to see if the token given by the form is exactly the same session found in the session. If it's true, then process the request else it's a double submission.
Example:
public class AuthenticationAction extends Action {
public void displayLogout(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
saveToken(request);
return mapping.findForward("displayLogout");
}
public ActionForward doLogout(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
if (isValidToken(request)) {
//It wasn't yet a double submission, delete token generated by Struts
resetToken(request);
//logout.
...
//return back home
return mapping.findForward("home");
} else {
//Double submission..
throw new Exception("double submission");
}
}
}
A better tutorial is found here.
Hmm, you can also use the Spring Webflow framework if you want, but the use of the back and refresh not submitting your forms twice can easely be solved by defining your controller right. I think the use of REST can also help solve some problems.
The hiddenfield manipulation is another thing since a hiddenfield can always be viewed in the source of your page. And if the field can be viewed then it is open to manipulation.
To avoid re-inventing the wheel, using an existing framework seems to be the best solution. Struts looks like a good candidate. A simple introduction tutorial is available.
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).