several servlet filter changing the response - java

Think about using several filters to change response
f1 should debug the response, f2 should reformat the content and then f3 should compress it all.
I red almost all blogs about filters and the essentials from oracle, but always without success.
Problem 1: As I understand getWriter has to be called in any case to be able to write the changed response back to the original response.
This leads to the problem, that getWriter was already called -exception is thrown in the chain.
Problem 2: Is it necessary to write the response even if was not changed?
Think about a condition which let the response in the filter unchanged.
I try to show what I am doing right now in a kind of pseudo code
//VERSION 01:
doFilter(){
if (condition to change response is true){
Printwriter out = response.getWriter();
OutputStreamResponseWrapper wrappedResponse = new OutputStreamResponseWrapper(httpServletResponse);
doFilter(originalRequest,wrappedResponse);
String convertedResponse = convertResponse(wrappedResponse.getContent());
out.write(convertedResponse);
out.close(); // without this it seems not to be send to the client??
}else{
doFilter(originalRequest,originalRequest);
}
}
//VERSION 02:
doFilter(){
Printwriter out = response.getWriter();
OutputStreamResponseWrapper wrappedResponse = new OutputStreamResponseWrapper(httpServletResponse);
doFilter(originalRequest,wrappedResponse);
if (condition to change response is true){
String convertedResponse = convertResponse(wrappedResponse.getContent());
out.write(convertedResponse);
}else{
out.write(wrappedResponse.getContent());
}
out.close(); // without this it seems not to be send to the client??
}
Now call 3 of these filters after each other with different conversions. I always get the "getWriter already called"-Exception.
I don't understand, because I pass always a wrapped response-object?
Perhaps somebody has a hint what is totally wrong with my approach. Thanks a lot in advance.

Related

How to test a HTTP request

I have set up this simple http request, which simply returns a "hello world" response to my IDE terminal. I have been looking into testing and I am not quite sure how i would test what this method is returning.
Currently i have done my own research into JUnit, but again i am not even sure if this would be the correct tool to use for this problem. I only researched this as it is a Java tool.
public static void newRequest() throws IOException {
URL helloServer = new URL("http://localhost:5050/");
HttpRequestFactory requestFactory = new NetHttpTransport().createRequestFactory();
HttpRequest request = requestFactory.buildGetRequest(new GenericUrl(helloServer));
HttpResponse rawResponse = request.execute();
String responseString = rawResponse.parseAsString();
logger.debug(responseString);
}
Any guidance on this would be greatly appreciated.
Does the function even need to be tested?
Does the function even need to be tested? Well, that is entirely up to you. Does this function contain code that is critical to your application? If so then yes. If the impact of a bug in this function is minimal then probably not.
Assuming that you want to test this, then:
The method in question is not returning anything void before the function name says this. You will need to look at testing the logic of the function. In this case you need to check that the correct response is received. There are two ways that I can think of to do this:
Modify the code to return the response.
You could change the function to return a String and then return rawResponse.parseAsString(); (which is the same thing you are logging.
Then you can call the function from the test and check the String that is returned.
Get the log message from your logger.
Depending on the logging that you are using, you could get the log message that was written by the function. Assuming log4j then there are some posts on how to do this:
log4j: how to get the last inserted log message?
Personally, I prefer the first option as it is less effort. I would also consider returning the body of the response rather than the raw response.

Issues With JAX-RS

I'm new to JAX-RS and having a number of issues (which oddly make me miss SOAP). Here is a snippet of my code. The getMergedPDFReport method should take a file and return a file after some processing. After which I would worry about the client
#GET
#Produces("application/pdf")
#Path("merge-service")
public Response getMergedPDFReport(#QueryParam(ApiParameters.WORD_DOCUMENT) File wordDocument,
#QueryParam(ApiParameters.MERGE_FIELDS)Object[] fieldNames,
#QueryParam(ApiParameters.MERGE_VALUES) Object [] fieldValues) {
ResponseBuilder builder =null;
try {
File product = DocumentUtil.generatePDF(wordDocument, fieldNames, fieldValues);
builder = Response.ok(product);
builder.header("Content-Disposition", "attachment; filename=\\\"report.pdf\\\"");
} catch (Exception e) {
e.printStackTrace();
}
return builder.build();
}
I get a warning on my server log that says "No injection source found for a parameter of type public javax.ws.rs.core.Response". I can't seem to know why.
2. Am I using the #QueryParam annotation right? Should I be using it for types of File, and arrays? I saw a lot of debates online over #BeanParam, #MatrixParam and #QueryParam. Since I didn't know what the first two do, I decided to Keep It Simple.
Any help would be appreciated.
I think you can't use queryParam for files. You must use a #Consumes with a multipart form.
Check this :
http://www.javatpoint.com/jax-rs-file-upload-example

Parsing a string with multiple variations

I am curious as to what a better way to deal with this is, I wanted to challenge my self and see if I could break up, in a HashMap of key,value (or String, String), a string that could come back in almost any format.
the string in question is:
/user/2/update?updates=success
Thats right, a url request for a server. The issue - as we all know this could be any thing, it could come back in any form. I wanted to break it up so that it would look like:
Controller => user
action => update
params => ??? (theres a 2, a update=success ... )
Obviously The above is not a real java object.
But you get the idea.
What do you need? what have you done? what are you trying to do?
What I want to do is map this to a controller and action while passing in the parameters along the way. But i need to separate this up making sure to specify each step what is what.
What I have done is:
private Filter parseRoute(String route){
String[] parsedRoute = route.split("[?:/=]");
Filter filter = new Filter(parsedRoute);
return filter;
}
Splits on any thing that is in the url (note, : would be something like /user:id/update
so: user/2/update ... )
I then attempted to do:
public class Filter {
private HashMap<String, String> filterInfo;
public Filter(String[] filteredRoute){
if(filteredRoute.length > 0){
filterInfo.put("Controller", filteredRoute[0]);
}else{
throw new RoutingException("routes must not be empty.");
}
}
}
But this is not going to work as I expected it to...As there are too many variables at play.
including parameters before the action (those would just be used to search for that user), their could be nested routes, so multiple controller/action/controller/action ..
How would you deal with this? What would you suggest? How could you get around this? Should you just do something like:
route(controller, action, params, template); ? (template lets you render a jsp). if so how do you deal with the ?update=success
I am using HttpServer to set up the basics. But I am now lost. I am trying to keep routing as generic and "do what ever you want we will map it to the right controller, action and pass in the parameters" but I think I bit off more then I can chew.
I have looked at both spark and spring framework, and decided that the route you pass, we will map to a xml file to find the controller and action, I just need the data structure in place to do that ...
So I am looking to back up and still go with "pass me something, ill map it out."
I would probably use the URL from apache,
org.apache.tomcat.util.net.URL url = null;
try {
url = new org.apache.tomcat.util.net.URL("/user/2/update?updates=success");
// ... do some stuff with it...
} catch (Exception e) {
e.printStackTrace();
}
java.net.URI may help you.
you can get your path by getPath()
and get all of your query by getQuery(),then you can split the query by = to name value pairs.
URI uri = new URI("/user/2/update?updates=success");
// /user/2/update
System.out.println("path is " + uri.getPath());
// updates=success
System.out.println("query is " + uri.getQuery());

How to get doc from couchdb without some fields? using Ektorp if possible

At first I misunderstood my problem and posted this question : Can someone explain me Cascading and FetchType lazy in Ektorp?
What I need to do: I need to save an Entity in couchdb and then have way to read it and potentially ignore some fields.
So I came up with this solution: I create a show function that delete fields from an object and then send it back.
function(doc, req) {
var result = doc;
var ignore = JSON.parse(decodeURIComponent(req.query.ignore)); //this is an array of field names
for (var i = 0, j = ignore.length; i < j; i++) {
if (result[ignore[i]]) {
delete result[ignore[i]];
}
}
return {
body : JSON.stringify(result),
headers : {
"Content-Type" : "application/json"
}
};
}
I have the same function but reversed in which the object keeps the fields I tell the function to keep.
Is there a better way to do this?
I also want to use Ektorp to call this but it allows me to only call Views. Right now I am forced to manage the http request myself. Is there a way to avoid this?
Right now this is the code I must use, but I would like to use Ektorp to do this.
HttpClient httpClient = new StdHttpClient.Builder().url("http://localhost:5984").build();
CouchDbInstance dbInstance = new StdCouchDbInstance(httpClient);
CouchDbConnector db = new StdCouchDbConnector("mydatabase", dbInstance);
db.createDatabaseIfNotExists();
String[] forget = new String[] { "field_to_ignore" };
String uri = "/mydatabase/_design/mydesigndoc/_show/ignorefields/mydocid?ignore=" + URLEncoder.encode(Json.stringify(Json.toJson(forget)), "UTF-8");
System.out.println(uri);
HttpResponse r = db.getConnection().get(uri);
String stuff = new Scanner(r.getContent()).useDelimiter("\\A").next();
System.out.println(stuff);
A show function isn't a terrible idea, from a CouchDB point of view. Ektorp may not support them, presumably because they're not hugely used, but Ektorp's open-source and on Github; you could easily just add this functionality, especially since you already have the basics of a working implementation of it.
Alternatively you could just build a view that does this for a given set of fields. You can't really parameterize this though, so you'd need well-defined sets of fields you know beforehand.
Finally I'd suggest either pulling the whole document and not worrying about it (unless you're in an extremely hugely bandwidth-limited situation it's probably not going to matter), or splitting the document into the constituent parts you're querying for and requesting them independently, if that's definitely the unusual case.

redirect from jsf?

I am working on application with jsp, jstl and jsf for my college project, thats being said, I am as well very new to jsf.
Everything is going great so far. However, I seems to have a problem figuring out how to do redirect from managed bean to page with dinamyc parameters.
For example article.jsp?article_id=2
Can somebody tell me how it is done ?
I been trying to use somethinng like
FacesContext.getCurrentInstance().getExternalContext().dispatch("faces/article.jsp2?article_id=" + articleId);
But get error:
javax.servlet.ServletException: #{postComment.postClick}: javax.faces.FacesException: javax.servlet.ServletException: javax.faces.component.UIViewRoot cannot be cast to com.sun.faces.application.StateManagerImpl$TreeNode
javax.faces.webapp.FacesServlet.service(FacesServlet.java:256)
I been trying to use
response.sendRedirect("faces/article.jsp2?article_id=" + articleId);
return;
But again getting an error.
javax.servlet.ServletException: Cannot forward after response has been committed
javax.faces.webapp.FacesServlet.service(FacesServlet.java:256)
Can somebody please tell me how do i redirect from managed java bean when working with jsf ?
Bellow is my code (maybe something wrong with that and thats why redirect not working).
HttpServletRequest request = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpServletResponse response = (HttpServletResponse) FacesContext.getCurrentInstance().getExternalContext().getResponse();
String articleId = request.getSession().getAttribute("article_id").toString();
//String articleId = request.getParameter("article_id");
String authorName = request.getSession().getAttribute("user_name").toString();
java.util.Calendar calendar = java.util.Calendar.getInstance();
String commentDate = String.valueOf(calendar.get(java.util.Calendar.DAY_OF_MONTH)) + ".";
commentDate += String.valueOf(calendar.get(java.util.Calendar.MONTH)) + ".";
commentDate += String.valueOf(calendar.get(java.util.Calendar.YEAR));
ArrayList error = new ArrayList();
if(commentName.contains("<"))
{
error.add("Comment name contains illegal characters");
}
if(commentBody.isEmpty() && commentBody.contains("<script"))
{
error.add("Your message body contains illegal characters");
}
if(error.size() > 0)
{
request.getSession().setAttribute("error", error);
error.clear();
FacesContext.getCurrentInstance().getExternalContext().dispatch("article.jsp2?article_id=" + articleId);
}
else
{
Comment comment = new Comment();
comment.setCommentAuthor(authorName);
comment.setCommentBody(commentBody);
comment.setCommentDate(commentDate);
comment.setCommentName(commentName);
comment.setArticleId(articleId);
DisplayArticleIO addComment = new DisplayArticleIO();
addComment.postComment(comment);
// FacesContext.getCurrentInstance().getExternalContext().dispatch("faces/article.jsp2?article_id=" + articleId);
response.sendRedirect("faces/article.jsp2?article_id=" + articleId);
return;
}
Thank you in advance.
In case some one will run into same problem.
That's what solved my problem:
FacesContext.getCurrentInstance().getExternalContext().redirect("article.jsp?article_id=" + articleId);
Why are you using dispatch in one place and redirect in the other? This isn't the source of the problem - not returning after sending responses, however, is. Other then that, if you don't mind, I have a few friendly suggestions:
You can use DateFormat to return the comment date as you want it (it will be much cleaner).
If the errors ArrayList only contains Strings, use generics (ArrayList<String>).
What are you doing with the errors?
Your sanitation of the commentName is very dangerous. You should use whitelisting instead of blacklisting - define what you wish to accept in a comment and block everything else. Right now someone could insert an <img> tag with a src pointing to a cookie stealing page which would result in a session hijack.
After changing the dispatch to a redirect add a return below it (you should always do this. Not doing this could result in what you're seeing right now, which is that you've already sent a response somewhere else, but since you haven't returned you've reached a place where you're trying to send another).
Basically, something is already sending output to the client before you make the call to response.sendRedirect(). Once something has been sent to the browser you can't redirect or forward them to a different place.
In general, any scenarios that might result in a redirect or a forward should be handled as early as possible in the request context to insure the redirect happens before you send any data to the client. Are you doing something like calling this code via a tag in the view?
FacesContext.getCurrentInstance().getExternalContext().redirect("http://www.myUrl.com");
René

Categories

Resources