Here is a little background of my problem:
I'm using Spring MVC 3.1.2.RELEASE. The server is deployed on Amazon AWS. I have a simple controller.
public class MyWebController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
try {
String delegateGuid = request.getParameter("delegateGuid");
String serviceCodesToBeUpdated = request.getParameter("serviceCodesToBeUpdated");
if (StringUtils.isBlank(delegateGuid) || StringUtils.isBlank(serviceCodesToBeUpdated)) {
throw new MyException("delegateGuid and/or serviceCodesToBeUpdted cannot be null or empty");
}
...
I have a client script that makes POST request to this endpoint. But sometimes, I hit this MyException that tells me the params are not set. But client logs show that the params are set correctly before sending the requests. The difficult part of debugging this is that it is not reproducible.
Does anyone know what could possibly have caused this issue? I know this might not be the level of detail enough to identify the problem. But if you can suggest any debug logs I could insert into my code, that would be helpful as well. I'm lost in that I don't even know where to start debugging this.
Thanks.
Related
TLDR: My method requires 2 redirects/forwards to work (1 for authentication and 1 to serve the jsp page). How can I resolve both redirects/forwards (or make it a non-requirement) so as to not run into the error, java.lang.IllegalStateException: Cannot forward after response has been committed.
For more context:
I have a java servlet with a method that looks something like the following:
#GET
#Path("/test")
#Authenticate
public Viewable test(#Context HttpServletRequest request, #Context HttpServletResponse response) {
Map<String, Object> model = createModel();
return new Viewable("/somePath/jspFile", model);
}
The #Authenticate annotation intercepts the call to do some Open ID Connect type authentication which results in the user being forwarded to a different server for all authentication needs. If the user is authenticated, they are redirected back to my application.
However, when hitting the url for this method, I am getting java.lang.IllegalStateException: Cannot forward after response has been committed. I don't know too much about using this Viewable class, but based on the fact that I don't run into that error when returning String/void/whatever else, I assume returning a new Viewable needs to do some forwarding that results in the user seeing the jsp page.
I've read the main SO post about this error, but I am unsure how to apply the fixes to my current problem. For example, I don't know how I would apply something like the following fix:
protected void doPost() {
if (someCondition) {
sendRedirect();
} else {
forward();
}
}
The fix assumes that I can I can either redirect OR forward, but my current method needs a redirect for authentication AND a forward/redirect to serve the jsp page. Maybe there's an obvious fix I'm missing that doesn't require a complete rehaul of the current code?
Edit: It would be nice if I could check if the user was authenticated first, but I assume using this annotation at all automatically entails an initial redirect
Edit: It looks like the user is redirected for the initial login authentication, but does not need to be redirected again after being authenticated once due to SSO
Ok based on some preliminary testing, it seems like the following solution has worked for me:
Check if the user has already been authenticated
Return a Response rather than a Viewable.
Since the user only needs to be redirected the first time for authentication, I can return an empty/meaningless response as a placeholder. And then once the user has been authenticated and is returned to my app, I can return a Viewable wrapped in a Response object.
So the code would look something like the following:
#GET
#Path("/test")
#Authenticate
public Response test(#Context HttpServletRequest request, #Context HttpServletResponse
response) {
Map<String, Object> model = createModel();
if (userIsAuthenticated()) {
return Response.status(401).build();
} else {
return Response.ok(new Viewable("/somePath/jspFile", model)).build();
}
}
I have a couple of sipring boot restfull APIs, that I want to communicate with, from a GWT based front-end. I've looked a bit on the Internet and found the RestyGWT framework, but as far as I've seen, all the documentation available is for using the embeded GWT server as a restfull API.
Can anyone please direct me to a usefull tutorial that I can follow.
Thanks to all.
I actually found a way to GET data through JsonPRequestBuilder, the problem now resides in POSTing data in json format.
final RequestBuilder reqBuilder = new RequestBuilder(httpMethod, url);
final Request request = reqBuilder.sendRequest(requestData, new RequestCallback()
{
#Override
public void onResponseReceived(Request request, Response response)
{
GWT.log(response.getText());
}
#Override
public void onError(Request request, Throwable exception)
{
}
}
httpMethod is something from com.google.gwt.http.client.Method like Method.GET
request is a String in which you pass the json.
response.getText will display the json.
To convert from object to json I would suggest to look at https://github.com/nmorel/gwt-jackson or https://github.com/vegegoku/gwt-jackson-apt (first one is older and has more features, second one is newer and better suited for future (GWT 3.0) but maybe has some features missing).
The last couple of days, I have been struggling with an issue. I've created a rest service hosted by a Grizzly server inside an OSGi container. Everything is working perfectly at this point.
Now, I want to add a header in every response.Not so complex or illogical right? Yet, I can't find a way to do it.
I have tried to:
1) Get the response object inside the rest functions as this question suggests (pretty textbook when you are not under OSGi).
2) Add a handler using the code above (in this case the service method is never called)
server.getServerConfiguration().addHttpHandler(
new HttpHandler() {
#Override
public void service(Request arg0, Response arg1)
throws Exception {
arg1.setHeader("Access-Control-Allow-Origin", "*");
}
});
I am using jersey-server/client/core 1.18.1 and grizzly2-server 1.18.1, hence i prefer a solution that can be applied in this version, but I am willing to update jar versions if it cannot be done in 1.18.x.
You could give a try to Jersey filters.
In a nutshell, you should create class implementing ContainerResponseFilter:
public class MyFilter implements ContainerResponseFilter {
#Override
public void filter(
ContainerRequest request,
ContainerResponse response
) throws IOException {
request.getHttpHeaders().add(<header name>, <header value>);
}
}
Then, you should register this filter in your Jersey server configuration.
Please, note, that this filter would be invoked on every response. To bind it only to specific resources, you could use annotation-binding, that is described here.
All other information you could find here.
I'm having the weirdest problem I have ever seen before.
The application I am working on uses spring security 3.1.3 to provide authentication support. There is a custom login form for which I have implemented a custom authenticationmanager / successhandler and failurehandler.
For some reason on internet explorer I always get the error message "Please fill in all mandatory fields". This is caused by appending /login?error=1 to the end of my url which can only be accessed through the following code (the redirectAndAddError method):
public class TideUserNamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public TideUserNamePasswordAuthenticationFilter() {
super();
}
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) {
String username = request.getParameter(SPRING_SECURITY_FORM_USERNAME_KEY);
String password = request.getParameter(SPRING_SECURITY_FORM_PASSWORD_KEY);
if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
redirectAndAddError(response);
return null;
}
return super.attemptAuthentication(request, response);
}
private void redirectAndAddError(HttpServletResponse response) {
try {
response.sendRedirect("/tide/login?error=1");
} catch (IOException e) {
throw new AuthenticationServiceException(e.getMessage(), e);
}
}
So what I tried was using Fiddler2, a web debugging proxy to view if one of the two parameters are actually empty. The strange thing is that when this program is running the error does not occur anymore and I can log on successfully.
Had anyone had a similar problem before? I think it's not related to my code as running the tool suddenly "solves" the problem.
This problem only occurs in internet explorer which makes it even more strange.
Edit
I have used another tool to watch the requests and this is what happens in IE:
First a POST request is sent to the uri /authenticate, I have set this myself like this:
<beans:property name="filterProcessesUrl" value="/authenticate"/>
The response of that request has http status code 302, moved temporarily and returns that the new location is at /login?error=1 (my form with the mandatory fields required error).
After that a GET request occurs to /login?error=1 with status code 401: Unauthorized. The intercept-url is set up like this:
<intercept-url pattern="/login**" access="permitAll"/>
The next request is a GET request to /login?error=1 again, this time the status code is showing: ERROR_INTERNET_CONNECTION_RESET, which looks like it could be a problem.
In Google Chrome the following request is made:
POST to /authenticate, result is a 302: moved temporarily to the dashboard page (which I display after logging on)
Someone on my team finally figured out what the problem was after finding this issue in the chromium bugtracker:
https://code.google.com/p/chromium/issues/detail?id=62687
The problem has been resolved by adding this in our login controller
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin() throws ServletException, IOException {
return "forward:/authenticate";
}
and changing the url that the form posts to to this one instead of the authentication url that spring security provides (we are redirecting to it manually now)
In order to debug failing requests I would like to print all information coming from HttpServletRequest.
Now, it's possible that a request will partially fail (for ex. Several matches are successful, yet one has failed) in which case I would like to catch the exception in the internal method that failed, print the error + the ServletUtil.toStringHttpServletRequest() and continue providing service (degraded but still useful vs. complete request failure).
Our current implementation either catches the exception and prints dumb info ("getRules failed") or throws the exception all the way to doGet() (effectively canceling service for the user) where as in doGet() I have access to HttpServletRequest where I can print at the relevant debug info (headers, parameters...).
Passing HttpServletRequest to every function called during the request that might fail seems a bit ugly, I will do it if no other elegant solution will pop up.
Making a before head ServletUtil.toStringHttpServletRequest() and storing it in a ThreadLocal map would be wasteful both in memory and CPU time. For some reason it feels wrong to store the HttpServletRequest object in ThreadLocal (please correct if I'm wrong).
Debug information is written both to local machine log and is emailed directly to devs (Great work log4j TLSSMTPAppender), so logging in several places won't be practical (Will need to assemble several emails to understand what's going on) and ssh'ing into the server is old age :) (We're all cloudy here... server might not exist by the time I get to look at the error)
So, my solution is gaining access to a "PrintErrorUtility" (TODO: better name it). That will receive (String errorMsg, Throwable t, HttpServletRequest) which will print the error together will all the relevant info... This will be called from internal try {} catch blocks that will notify about the error but will not cancel the request because of it.
Obviously I'm taking about servers running in production.
Comments? Please advise.
Thank you, Maxim.
Do this task in a Filter after the FilterChain#doFilter() call. The ServletRequest object is already there. In the business code where this exception is to be suppressed gracefully, store the exception as a request attribute and just let the Filter check/grab it from the request.
Update: as per the comments, here's an example:
public class Context {
private static ThreadLocal<Context> instance = new ThreadLocal<Context>();
private HttpServletRequest request;
private List<Exception> exceptions = new ArrayList<Exception>();
private Context(HttpServletRequest request) {
this.request = request;
this.request.setAttribute("exceptions", exceptions);
}
public static Context getCurrentInstance() {
return instance.get();
}
public static Context newInstance(HttpServletRequest request) {
Context context = new Context(request);
instance.set(context);
return context;
}
public void release() {
instance.remove();
}
public void addException(Exception exception) {
exceptions.add(exception);
}
}
And here's how to use it in your controller servlet:
Context context = Context.newInstance(request);
try {
executeBusinessCode();
} finally {
context.release();
}
And here's how you could use it in the executed business code:
} catch (Exception e) {
Context.getCurrentInstance().addException(e);
}