i write a custom spring scope base on FacesContext Logique,
public class DynamicScope implements Scope{
#Override
public Object get(String name, ObjectFactory<?> objectFactory) {
AbsErpFolder erpFolder = null;
if (FacesContext.getCurrentInstance()!=null)
erpFolder = (AbsErpFolder)FacesUtils.getExternalContext().
getRequestMap().get( ErpFolderKey );
............
}
Now i need to instanciate a bean in FileServlet Filter using
WebApplicationContext wsc = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
IGenericService erpFileService = (IGenericService) wsc.getBean("erpFileService");
The problem is during the execution my ServletFile the current FacesContext is null (the dynamic scope can't work ) so how to get the current request ?
ThreadLocal should do the trick
( Defined in my first Filter )
public static ThreadLocal servletRequestHolder = new ThreadLocal();
public static HttpServletRequest getCurrentRequest(){
return (HttpServletRequest) servletRequestHolder.get();
}
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
servletRequestHolder.set( request );
...........
}
Related
Hi all I want to create RedirectionFilter at java spring. The main purpose is when status code 302 is detected then send redirect and replacing the response content by custom text content. The first problem is don't know how to catch the response code 302. This is my current thinking .
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) (request);
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
String redirectURL="www.google.com";
if(statuscode == 302 ){
httpServletResponse.sendRedirect(redirectURL);
}
Something like that. I have out of ideas. Thanks for helping.
You can use HandlerInterceptorAdapter to get the response after each call and can validate the response code and do necessary things
#Component
public class TestInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object object) throws Exception {
System.out.println("test");
return true;
}
#Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, java.lang.Object handler, #org.springframework.lang.Nullable java.lang.Exception ex) throws java.lang.Exception {
if(response.getStatus()==302){
// your code
}
}
}
After creating a interceptor need to register it in InterceptorRegistry
#Component
public class InterceptorsConfig implements WebMvcConfigurer {
#Autowired
private TestInterceptor testInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor);
}
}
Once triggering a request, the control will come to interceptor first.
Restcontroller sample
#RestController
#RequestMapping("/test")
public class Restcontroller {
#GetMapping
public ModelAndView redirectWithUsingRedirectPrefix(ModelMap model) {
model.addAttribute("attribute", "redirectWithRedirectPrefix");
return new ModelAndView("redirect:/redirectedUrl", model);
}
}
I've setup a Spring HandlerInterceptor to add an attribute to the HttpServletRequest to be able to read it from the Controller, sadly this does not seem to work which seems strange to me. Am I doing things wrong? Any idea how to transmit the data from the Interceptor to the Controller?
Here is the simplified code of the two impacted classes
public class RequestInterceptor implements HandlerInterceptor {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
request.setAttribute("my-role", "superman");
}
[...]
}
#RestController
#RequestMapping("Test")
public class TestController {
public final Logger logger = LoggerFactory.getLogger(getClass());
#RequestMapping(value = "something")
public void something(HttpServletRequest request) {
logger.info(request.getAttribute("my-role"));
}
[...]
}
The request.getAttribute("my-role") returns null... but does return the excepted value if I read it in the postHandle of the HandlerInterceptor, I feel like I'm missing something...
EDIT : I found out that going thru the session with "request.getSession().setAttribute" works as a charm, still i do not understand why the request itself does not work in this use case.
Can you try with session instead of request like below.
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
...
HttpSession session = request.getSession();
session.setAttribute("attributeName", objectYouWantToPassToHandler);
....
}
In your handler handleRequest method:
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
....
HttpSession session = request.getSession();
objectYouWantToPassToHandler objectYouWantToPassToHandler = session.getAttribute("attributeName");
....
}
Is it possible to access RedirectAttributes in method without RedirectAttributes in signature? For example, when overriding method like one below:
#Override
public void onAuthenticationSuccess(final HttpServletRequest req, final HttpServletResponse res,
final Authentication auth) throws IOException, ServletException {
// add something to RedirectAttributes here
// redirectAttributes.addFlashAttribute("attr", "value");
super.onAuthenticationSuccess(req, res, auth);
}
I'm using spring 3.2.2.RELEASE.
As you can see in the DispatcherServlet class implementation, there are constants:
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
Spring has a class called RequestContextUtils, which has methods:
public static Map<String, ?> getInputFlashMap(HttpServletRequest request)
public static FlashMap getOutputFlashMap(HttpServletRequest request)
public static FlashMapManager getFlashMapManager(HttpServletRequest request)
The first two methods will give you an access to input and output flash maps respectively.
The last method returns FlashMapManager, which has a number of convinient methods to work with flash attributes. See implementations of this interface for details, specifically AbstractFlashMapManager.
If your goal is "to add indication that the customer has landed on the home page for the first time," then HttpSession may do the trick:
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException
{
...
boolean firstLogin = <determine whether this is the first login>;
<reset condition that caused firstLogin to be true>;
...
HttpSession session = request.getSession(false);
if (session != null) {
session.setAttribute("firstLogin", firstLogin);
}
else {
log.debug("No session");
}
}
// Controller for some page
#RequestMapping(value = <your page>, method = RequestMethod.GET)
public String showPage(<some other args>, HttpSession session)
{
...
Object firstLogin = session.getAttribute("firstLogin");
Assert.isInstanceOf(Boolean.class, firstLogin, "firstLogin");
if ((Boolean)firstLogin) {
<handle first login>;
}
...
return <page>;
}
This works for me. The logic behind this is that the login is in the context of the entire session that, presumably, comprises multiple requests.
I have an independent project for writing test cases; the problem is I can't mock HttpServletRequest, simply because in my servlet there are calls like getServletContext() as test cases are running from the outside servlet container. It will always return an error saying "no context found". This is just one dependency with the servlet container; there can be hundreds. For example, initialContext.lookup() also depends on a container.
How can I use Mockito to write a test case in this scenario? Please don't ask for an error message; it's more of a logical problem than technical.
Looking on the internet for tutorials makes me wonder if I am doing something seriously wrong. No one seems to have encountered this problem before... How can you mock HttpServletRequest without ever having getServletContext() called in the servlet? I mean seriously, how rare can it be?
You have a servlet implementation that uses the ServletContext, e.g.
public class SomeServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletContext();
Object attribute = servletContext.getAttribute("test");
System.out.println(attribute.toString());
}
}
in this case you have 2 options to test the doGet method
Use powermock's partitial mocking to only mock the getServletContext method.
#RunWith(PowerMockRunner.class)
public class SomeServletTest {
#Test
public void onGet() throws ServletException, IOException{
SomeServlet someServlet = PowerMock.createPartialMock(SomeServlet.class, "getServletContext");
ServletContext servletContext = PowerMock.createNiceMock(ServletContext.class);
HttpServletRequest httpServletRequest = PowerMock.createNiceMock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = PowerMock.createNiceMock(HttpServletResponse.class);
someServlet.getServletContext();
PowerMock.expectLastCall().andReturn(servletContext);
servletContext.getAttribute("test");
PowerMock.expectLastCall().andReturn("hello");
PowerMock.replay(someServlet, servletContext, httpServletRequest, httpServletResponse);
someServlet.doGet(httpServletRequest, httpServletResponse);
}
}
or a simpler way is to just override the getServletContext method. In this case you don't need powermock. You can just do it using easymock. e.g.
public class SomeServletTest {
#Test
public void onGet() throws ServletException, IOException{
HttpServletRequest httpServletRequest = EasyMock.createNiceMock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = EasyMock.createNiceMock(HttpServletResponse.class);
final ServletContext servletContext = EasyMock.createNiceMock(ServletContext.class);
SomeServlet someServlet = new SomeServlet(){
public ServletContext getServletContext() {
return servletContext; // return the mock
}
};
EasyMock.expect(servletContext.getAttribute("test")).andReturn("hello");
EasyMock.replay(servletContext, httpServletRequest, httpServletResponse);
someServlet.doGet(httpServletRequest, httpServletResponse);
}
}
there can be 100's. like initialContext.lookup() also dependent on container.
In this case you can either create an InitialContext mock and use this.
If your code creates a new InitialContext, e.g.
public void someMethod(){
InitialContext context = new InitialContext();
context.lookup(....);
}
you can simply extract the InitialContext instantiation to a protected method that you can override in your tests like I showed above with the ServletContext
public void someMethod(){
InitialContext context = createInitialContext();
context.lookup(....);
}
protected InitialContext createInitialContext(){
return new InitialContext(); // can be overridden by a subclass
// and therefore by tests as well to
// return a mock
}
If you don't want or you can't modify the code in this way, then you can use Powermock to intercept the constructor.
EDIT
Can you post your Mockito code? It would be a pleasure, since the methods are named differently.
#Test
public void onGet() throws ServletException, IOException {
HttpServletRequest httpServletRequest = Mockito.mock(HttpServletRequest.class);
HttpServletResponse httpServletResponse = Mockito.mock(HttpServletResponse.class);
final ServletContext servletContext = Mockito.mock(ServletContext.class);
SomeServlet someServlet = new SomeServlet(){
public ServletContext getServletContext() {
return servletContext; // return the mock
}
};
Mockito.doReturn("hello").when(servletContext).getAttribute("test");
someServlet.doGet(httpServletRequest, httpServletResponse);
}
i want to ask you about mvc. How it works. So, this is simple example(I don't use any frameworks)
in Controller(Servlet):
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
processRequest(request, response);
}
private void processRequest(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String page = null;
AbstractCommand action;
action = ActionFactory.getAction(request);// get command from factory
page = action.execute(request, response);
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(page);
dispatcher.forward(request, response);
}
for action we create a common interface(Strategy pattern):
public interface AbstractAction {
public String execute(HttpServletRequest request, HttpServletResponse response);
}
Simple Action(Example):
public class HelloAction implements AbstractAction {
#Override
public String execute(HttpServletRequest request,
HttpServletResponse response) {
//....(some actions to modify request)
String page = "/main.jsp";
return page;
}
}
And now, our factory:
public class ActionFactory {
private enum Actions{
HELLO;
}
public static AbstractAction getAction(HttpServletRequest request){
String action = request.getParameter("action");//take parameter from jsp
Actions actionEnum = Actions.valueOf(action.toUpperCase());
switch (actionEnum) {
case HELLO:
return new HelloAction();
}
}
}
We came to the place where I am in confused. Servlet is initialized only once, and only one for all requests. Just forwards requests to the actions where we modify request or response. But, we create NEW instance of the class for every request. Here can occur memory overflow!? Or not?
Can we make these actions static(static method, one for all request)? If two requests come at the same time what will happen to them?
What do you think about this, please share your experience.
P.S. sorry for bad english.
How about Singleton pattern to get the instance of the Action class ?
Just add some abstact getInstance() method in AbstractAction.
Make every implementation provide its own instance.
In every implementation class, use Singleton pattern so that only one instance exists.
Make sure no action class stores any data related to a specific request.
As i understood the jsp, the whole thing is stateless, if u access the servlet by http request, the servlet will be created in a new instance.
After leaving the servlet by .forward(), it will be released by garbage collection.
2,3,...,n requests = 2,3,...,n servlets.
by forwarding to a jsp, the only way to access the servlet from jsp is a new http request = new servlet. ( will move to the doPost method)