I am using Liferay Portal 6.0. version. I am creating hooks plugin for redirecting to new community whenever user request. I have overridden run method in ServicePreAction like this:
protected void doRun(HttpServletRequest request, HttpServletResponse response)
throws Exception {
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
if(some condition) {
response.sendRedirect("/web/mycommunity/home");
}
}
But i am geting "Too Many Redirects" Error.
Any solution?
Related
I implemented rest web services with Spring. When I deployed it in Eclipse as a Spring Boot Application, it works. However when I deployed it in Tomcat 7 on the same machine, it does not work. The error message is as follows:
XMLHttpRequest cannot load http://localhost:8080/ristoreService/oauth/token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8081' is therefore not allowed access.
My CORS filter looks like this:
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8081");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me, "
+ "Origin,Access-Control-Request-Method, Access-Control-Request-Headers, Authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
If I comment out response.setHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8081");, I still get the same error. It wouldn't work without this line even if I deploy in Eclipse. Why does it act differently being deployed under different environment on the same ip?
EDIT:
I tested the url http://localhost:8080/ristoreService/oauth/tokenwith rest client tester "CocoaRestClient" and got 404. So I made up a url which apparently does not exist http://localhost:8080/xxxxx and run it in UI (angularjs) and again got the CORS error. I think the error is kind of misleading, it is after all a 404. But why does it complain not found when the war was deployed successfully with the name ristoreService.war under webapps in Tomcat?
Try using a FilterRegistrationBean. Looks like this in Java Config:
#Bean
public FilterRegistrationBean authorizationFilter(){
FilterRegistrationBean filterRegBean = new FilterRegistrationBean();
filterRegBean.setFilter(authorizationFilter);
List<String> urlPatterns = new ArrayList<String>();
urlPatterns.add("/v1/*");
filterRegBean.setUrlPatterns(urlPatterns);
return filterRegBean;
}
Any reason why you're not using Spring Boot's CORS capabilities? It's already supported out of the box, you just gotta configure it. You can enable it globally like this:
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
According to How to deploy Spring Boot application, I have to make main application to extend SpringBootServletInitializer. Once I added that, it works.
To solve CORS issue I used #CrossOrigin. And I did not implement my own CORS filter. Any way spring already have provided few addition solutions for CORS issue.
If you need only your filter you could use it in this way:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(yourFilter);
...
}
I have a Spring Boot web app that runs just fine from STS but shows different behavior when running in Tomcat from a WAR file.
I use Thymeleaf to handle all my web pages but I have a couple pages that are using jQuery to send async calls and make user experience more dynamic.
Anyway, I have a Controller method that calls a service method which may throw a RuntimeException which I handle this way :
#ExceptionHandler(MyRuntimeException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
public #ResponseBody String handleMyRuntimeException(MyRuntimeException exception) {
return "Oops an error happened : " + exception.getMessage();
}
In JS, I use the response body I return above to display a message on screen.
That works perfectly fine when running my app in STS but once I switch to deploy it in Tomcat the ErrorPageFilter gets invoked and in doFilter() it does:
if (status >= 400) {
handleErrorStatus(request, response, status, wrapped.getMessage());
response.flushBuffer();
}
In handleErrorStatus() it creates an error with the status and associated message but doesn't return my response.
I haven't figured out how to solve this and I'd really appreciate if anybody could help.
Thanks!
I went around this issue (I would think that is a Spring Boot issue) by doing the following.
Separate Rest and Mvc controllers
See my question here : Spring MVC: Get i18n message for reason in #RequestStatus on a #ExceptionHandler
Inject Jackson converter and write response myself :
#ControllerAdvice(annotations = RestController.class)
#Priority(1)
#ResponseBody
public class RestControllerAdvice {
#Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
#ExceptionHandler(RuntimeException.class)
#ResponseStatus(value = HttpStatus.BAD_REQUEST)
public void handleRuntimeException(HttpServletRequest request, HttpServletResponse response, RuntimeException exception) {
try {
jacksonMessageConverter.write(new MyRestResult(translateMessage(exception)), MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
response.flushBuffer(); // Flush to commit the response
} catch (IOException e) {
e.printStackTrace();
}
}
}
I'm listening for a window close event:
closeHandlerReg = Window.addCloseHandler(new CloseHandler<Window>() {
#Override
public void onClose(CloseEvent<Window> event) {
// ...
}
});
The documentation says that no UI can be shown in that callback. What about GWT RPC calls? I'm trying to make one, but it isn't showing up on the server (either in breakpoints or log statements).
Problem is that GWT RPC is asynchronous and the calls to RPC services return immediately. In this case the window is closed before the browser has a chance to send the underlying XMLHTTPRequest.
If it's absolutely necessary you should be able to hand-craft calling some sort of servlet (not GWT RPC) with a "synchronous" XMLHTTPRequest. Have a look here for an example: http://weblogs.asp.net/bleroy/archive/2005/12/15/433278.aspx
But really you shouldn't be doing anything of this sort in the window.onunload or window.onbeforeunload (these are the underlying DOM events for CloseEvent and ClosingEvent for the Window. Perhaps there is a better way to do what you are trying to do.
The use case you have should be possible. When you make the RPC call in the closeHandler it should arrive at the server, because while it returns directly, it has started sending the data, and set a callback to wait for the result. However the callback will fail because the connection is lost because the window is closed. But that is no problem as you only want to notify the server. So the question might be what are you sending? and does it work at all, when you send it at some other point in the code, not in the closeHandler?
Old question, but still - maybe someone faces the same issue.
RPCs won't work in the closing handler as already discussed. This workaround worked for me:
In the onClose method, do something like:
Window.Location.replace(GWT.getModuleBaseURL() + "rpcCall?param1=" + param1 + "¶m2=" + param2);
whereas "rpcCall" is the name of the rpc url you have set in your web.xml file. Of course, a random number of parameters may be passed within the URL.
Then, in your server-side implementation of your rpc interface, you can override the doGet method:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) {
String param1 = URLDecoder.decode(request.getParameter("param1"), "UTF-8");
String param2 = URLDecoder.decode(request.getParameter("param2"), "UTF-8");
// do something
}
And another solution: Don't do an rpc call on window closing, but a regular http call that can then be handled by a custom servlet on the server side.
In your GWT module, do something like this:
Window.addWindowClosingHandler(new ClosingHandler() {
#Override
public void onWindowClosing(ClosingEvent event) {
sendWindowClosed(GWT.getModuleBaseURL() + "teardownservice");
}
});
private native void sendWindowClosed(String url)
/*-{
var Http = new XMLHttpRequest();
Http.open("GET", url);
Http.send();
}-*/;
}
In the server-side servlet, you can then handle this call:
public class TearDownServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
.... whatever you want ....
}
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
StatusCodeException Vs. RuntimeException in GWT
I want to trigger RPC callback "onFailure" if the session expires in the server.
I created a custom RPC AsyncCallback that handles the "session expired" event from the server.
I overrode RemoteServiceServlet to validate the session prior to invoking the method. So basically, it is not the declared method that throws the exception but the custom RemoteServiceServlet. It still goes to the "onFailure" in the client async but the Throwable object is still of type "StatusCodeException" without the EXPIRED_SESSION_MSG message. Any ideas?
Custom RemoteServiceServlet:
public class XRemoteServiceServlet extends RemoteServiceServlet {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession(false);
if (session != null) {
final String sessionIdFromRequestHeader = getSessionIdFromHeader();
if (!isNullOrEmptyString(sessionIdFromRequestHeader)) {
final String sessionId = session.getId();
if (!sessionId.equals(sessionIdFromRequestHeader)) {
throw new RuntimeException(EXPIRED_SESSION_MSG);
}
}
Custom AsyncCallback:
public class XAsyncCallback<T> implements AsyncCallback<T> {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
public void onFailure(Throwable caught) {
final String message = caught.getMessage();
if (!isNullOrEmptyString(message) && message.contains(EXPIRED_SESSION_MSG)) {
com.google.gwt.user.client.Window.Location.reload();
}
}
#Override
public void onSuccess(T arg0) {
}
/**
* Returns true if the string is null or equals to the empty string.
*
* #param string the string to test
* #return true if the string is empty
*/
private static boolean isNullOrEmptyString(String string) {
return string == null || "".equals(string);
}
}
See here for handling exceptions with GWT RPC.
An "expected failure" is an exception thrown by a service method that is declared in the signature of the service method. These exceptions are serialized back to the client.
"Unexpected expections" are errors that are not part of the service method's signature, or that result from SecurityExceptions, SerializationExceptions, or other failures within the RPC framework.
What you want is a checked exception, because you want to send it back to the client and do something about it. The RPC framework is in charge of catching it, serializing it and calling the onFailure method with the right exception. In order to do that, you need to follow its guidelines which are :
You need to specifiy in the service
signature that the exception can be
thrown.
The exception must be thrown
in the service implementation method.
What you're doing is throwing an unexcepted exception from some method that shouldn't even be throwing exceptions. So RPC doesn't know what really happened and sends back a generic message saying 'Hey, something unexpected happened, look at the server log'.
I understand that you want to check the session on every call. Your easiest option is to have a method to check that in your servlet implementation and call it from all your service methods.
Otherwise, you can try to override the GWT RPC framework by looking at the class
com.google.gwt.user.server.rpc.RPC
but that's pretty advanced stuff.
If you want to send exceptions via GWT-RPC you must use checked exceptions. RuntimeException is an unchecked exception so you can not use it in this case.
Create your own exception that extends Exception and implements Serializable. Also, you must indicate on methods declaration that this method might throw an exceptions:
In my GWT app. I overrode RemoteServiceServlet to check if the session is valid right before the service method is being called. I am trying to throw a RuntimeException("expired session") from the server and I would like the client to catch this exception from the asynccallback onFailure...
In the client I would like to:
Asynccallback:
#Override
public void onFailure(Throwable caught) {
final String message = caught.getMessage();
if (!isNullOrEmptyString(message) && message.contains("expired session")) {
com.google.gwt.user.client.Window.Location.reload();
}
}
However, in the client, the caught object is still a StatusCodeException and the message is still the default "...Exception in the server...". how can I override the exception at least the default message to compare if it was a session expired message I sent from the server?
thanks
Hi Gursel,
Here's my code:
-> Custom RemoteServiceServlet. I'm trying to "intercept" every method before it's invoked. I check the session and throw a RuntimeException if it's already expired. So basically, it is not the declared method that throws the exception but the custom RemoteServiceServlet. It still goes to the "onFailure" in the client async but the Throwable object is still of type "StatusCodeException" without the EXPIRED_SESSION_MSG message. Don;t know how to make this work. Thanks!
public class XRemoteServiceServlet extends RemoteServiceServlet {
private final static String EXPIRED_SESSION_MSG = "ERROR: Application has expired session.";
#Override
protected void onAfterRequestDeserialized(RPCRequest rpcRequest) {
HttpServletRequest httpServletRequest = this.getThreadLocalRequest();
HttpSession session = httpServletRequest.getSession(false);
if (session != null) {
final String sessionIdFromRequestHeader = getSessionIdFromHeader();
if (!isNullOrEmptyString(sessionIdFromRequestHeader)) {
final String sessionId = session.getId();
if (!sessionId.equals(sessionIdFromRequestHeader)) {
throw new RuntimeException(EXPIRED_SESSION_MSG);
}
}
All RuntimeExceptions thrown by Server side of gwt application has been wrapped as StatusCodeException if you did not declare them at your remote method declaration.
EDIT :
After, Thomas Broyer comment, I have learned that all exceptions (checked or unchecked) that are declared at remote method declaration are propagated to gwt client. Therefore all you have to do is just declare your remote method such as :
public void myRemoteMethod() throws RuntimeException;
The post looks too old, still here is the solution I have come up with. Override processCall(String payload) of RemoveServiceServlet, if the session is invalid execute the blow code else call super.processCall(payload).
//Pass the exception to Client
RPCRequest rpcRequest = RPC.decodeRequest(payload, this.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
return RPC.encodeResponseForFailure(rpcRequest.getMethod(), new CustomException("Invalid Session!"),rpcRequest.getSerializationPolicy(), rpcRequest.getFlags());
All the GWT services are servlets so GWT serializes the custom exception and sends to client as string, we follow the same :)