Hi I am a beginner in junit's and I got stumbled upon the junit of init() method which I defined in my servlet.
Here is my servlet.
public class EmailSendingServlet extends HttpServlet{
private static final long serialVersionUID = -7796409155466523414L;
/**
* Creates an Email Model Object
*/
Email emailMessage = new Email();
/**
* Overrides the init constructor of servlet
*
*/
public void init() {
ServletContext context = getServletContext();
emailMessage.setHostName(context.getInitParameter("host"));
emailMessage.setPortName(context.getInitParameter("port"));
}
/**
* Overrides the Service method of Generic Servlet
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
emailMessage.setFrom(request.getParameter("from"));
emailMessage.setRecipient(request.getParameterValues("recipients"));
emailMessage.setSubject(request.getParameter("subject"));
emailMessage.setBody(request.getParameter("body"));
emailMessage.setFile(request.getParameterValues("file"));
String resultMessage = "";
try {
EmailUtility.sendEmail(emailMessage);
resultMessage = "The Email was sent successfully";
request.setAttribute("message", resultMessage);
response.setContentType("text/html");
RequestDispatcher view = request.getRequestDispatcher("/Result.jsp");
view.forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
and given below is the test case of my servlet class:
#RunWith(PowerMockRunner.class)
public class EmailSendingServletTest extends Mockito
{
#Test
public void TestEmailSendingServlet() {
HttpServletRequest request = mock(HttpServletRequest.class);
HttpServletResponse response = mock(HttpServletResponse.class);
RequestDispatcher requestDispatcher = mock(RequestDispatcher.class);
when(request.getParameter("from")).thenReturn("robi#robi.com");
String[] recipients = new String [3];
recipients[0] = "abc#abc.com";
recipients[1] = "xyz#xyz.com";
recipients[2] = "qwe#qwe.com";
when(request.getParameterValues("recipients")).thenReturn(recipients);
when(request.getParameter("subject")).thenReturn("Test Mail");
when(request.getParameter("body")).thenReturn("This is Body");
String[] files = new String[1];
files[0] = "C:\\Users\\asara3\\Documents\\Architecture.jpg";
when(request.getParameterValues("file")).thenReturn(files);
when(request.getRequestDispatcher("/Result.jsp")).thenReturn(requestDispatcher);
try {
new EmailSendingServlet().doPost(request, response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I am bit confused to stub the context.getInitParameter("host") in my test case ? Any help guys ?
You could use the spy() method of Mockito to mock the behavior of the getServletContext() method.
For example add this in your setup() method or in the constructor of the unit test class :
public class EmailSendingServletTest {
...
private EmailSendingServlet emailSendingServlet;
private EmailSendingServlet emailSendingServletSpy;
...
public EmailSendingServletTest(){
emailSendingServlet = new EmailSendingServlet();
emailSendingServletSpy = Mockito.spy(emailSendingServlet);
}
}
Then you may mock the getServletContext() method like that :
Mockito.doReturn(yourMockedServletContext).when(emailSendingServletSpy.getServletContext());
Generally I avoid spying (that mocks the object under test) but in the case of third-party dependency as servlet, it is an acceptable case as refactoring is not able or else it forces us to write no standard changes in the way the third-party dependency is used. Which is often undesirable too.
Related
I'm trying to call a Servlet that writes the javaobject taken from database in json format from another Servlet.
The flow of my code is Servlet1 check_login -> Servlet2 jsonCreate
I'm getting HTTP 404 error when I try to do that.
Here is my check_login.java Servlet code
#WebServlet("/Check_login")
public class Check_login extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String user_name=request.getParameter("user_name");
String password=request.getParameter("password");
try {
String role=check_database(user_name,password);
if(role.equals("")) {
response.sendRedirect("index.html");
}else if(role.equals("admin")) {
List<Programs> Programs_Offered = new ArrayList<Programs>();
RequestDispatcher rd = request.getRequestDispatcher("jsonCreate");
rd.forward(request,response);
}else if(role.equals("mac")) {
response.sendRedirect("mac_welcome.jsp");
}
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}
}
And, here is jsonCreate.java Servlet code
#WebServlet("/jsonCreates.json")
public class jsonCreate extends HttpServlet {
public static List<Programs> list() throws SQLException, IOException {
List<Programs> Programs_Offered = new ArrayList<Programs>();
Connection conn=DataBase_Connection.getInstance().getConnection();
Statement ps=conn.createStatement();
ResultSet rs = ps.executeQuery(Queries.view_programs);
while(rs.next()){
Programs p=new Programs();
p.setProgramName(rs.getString("ProgramName"));
p.setDescription(rs.getString("Description"));
p.setApplication_Eligibility(rs.getString("Applicant_Eligibility"));
p.setDuration(rs.getInt("Duration"));
p.setDegree_Certificate_Offered(rs.getString("Degree_Certificate_Offered"));
Programs_Offered.add(p);
}
return Programs_Offered;
}
private static final long serialVersionUID = 1L;
public jsonCreate() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Programs> categories=null;
try {
categories = jsonCreate.list();
} catch (SQLException e) {
e.printStackTrace();
}
String categoriesJson = new Gson().toJson(categories);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(categoriesJson);
//response.sendRedirect("admin_welcome.jsp");
}
when I make the name of jsonCreates.json same as java servlet Name (jsonCreate) it runs fine and opens the json data on page at URL http://localhost:8081/servlet_demo/jsonCreate.
Then again when I re-direct to a new JSP admin_welcome.jsp it opens without any problem but I don't find any json data available in the link http://localhost:8081/servlet_demo/jsonCreate.
I'm commiting some mistake and I'm not able to find it. Can someone tell what's missing in this.
You should set the name of jsonCreates.json same as java servlet Name (jsonCreate)
#WebServlet("/jsonCreate")
The reason why you dont get the json data is because response.sendRedirect() does not forward any data, it just makes a redirection(navigation) to a page.
If you want your JSON data to be accessible throughout your page navigations then you should create a session and set a session variable to hold this json data.
JAVA
HttpSession session = request.getSession(false);
session.setAttribute("variable", "json value");
response.sendRedirect("/page");
JSP
<%
out.println(session.getAttribute("variable"));
%>
OR
you can use forward() as below:
JAVA
request.setAttribute("variable", "JSON data");
RequestDispatcher dispatcher = servletContext().getRequestDispatcher(url);
dispatcher.forward(request, response);
JSP
<%
out.println(request.getAttribute("variable"));
%>
Is there an offical way to mock a rest-easy asynchronous HTTP request?
The sample code:
#GET
#Path("test")
public void test(#Suspended final AsyncResponse response) {
Thread t = new Thread() {
#Override
public void run()
{
try {
Response jaxrs = Response.ok("basic").type(MediaType.APPLICATION_JSON).build();
response.resume(jaxrs);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
t.start();
}
I offen mock rest-easy's request this way:
#Test
public void test() throws Exception {
/**
* mock
*/
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(action);
MockHttpRequest request = MockHttpRequest.get("/hello/test");
request.addFormHeader("X-FORWARDED-FOR", "122.122.122.122");
MockHttpResponse response = new MockHttpResponse();
/**
* call
*/
dispatcher.invoke(request, response);
/**
* verify
*/
System.out.println("receive content:"+response.getContentAsString());
}
BUT it dosn't work. I got a BadRequestException during the unit test.
What's the right way to mock a rest-easy asynchronous HTTP request?
By reading rest-easy's source code, I finally find a way to work around with asynchronous HTTP request :
#Test
public void test() throws Exception {
/**
* mock
*/
Dispatcher dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(action);
MockHttpRequest request = MockHttpRequest.get("/hello/test");
request.addFormHeader("X-FORWARDED-FOR", "122.122.122.122");
MockHttpResponse response = new MockHttpResponse();
// Add following two lines !!!
SynchronousExecutionContext synchronousExecutionContext = new SynchronousExecutionContext((SynchronousDispatcher)dispatcher, request, response );
request.setAsynchronousContext(synchronousExecutionContext);
/**
* call
*/
dispatcher.invoke(request, response);
/**
* verify
*/
System.out.println("receive content:"+response.getContentAsString());
}
The output of response is correct !!!
I have a static 404 page with fancy stuff in it.
In case the user enters a wrong url of a page that does not exist, I would like him to see that 404 page , but also would like to keep the url as is in order for user to see what mistake s/he has done typing the url .
The page entered and that does not exist :
http://localhost:10039/my.website/my/halp.html
The 404 page :
http://localhost:10039/my.website/my/notfound.html
Briefly, instead of using "sendRedirect" here, I would to "get content" of pageNotFoundUrl and show it while the url is still http://localhost:10039/my.website/my/halp.html
Instead of redirect, I also tried "forward" as Kayaman suggested but in this case I get " Cannot forward. Response already committed."
TestServlet is defined in web.xml , and this class extends UtilFreemarkerServlet which extends FreemarkerServlet.
UtilFreemarkerServlet
public abstract class UtilFreemarkerServlet extends FreemarkerServlet {
private static final long serialVersionUID = 1L;
public static final String REQUEST_OBJECT_NAME = "RequestObject";
private Logger logger = LoggerFactory.getLogger(getClass());
#Override
public void init() throws ServletException {
logger.info("init started");
super.init();
Configuration cfg = getConfiguration();
cfg.setLocalizedLookup(false);
}
#Override
protected ObjectWrapper createObjectWrapper() {
return ObjectWrapper.BEANS_WRAPPER;
}
#Override
protected HttpRequestParametersHashModel createRequestParametersHashModel(HttpServletRequest request) {
request.setAttribute(REQUEST_OBJECT_NAME, request);
return super.createRequestParametersHashModel(request);
}
}
TestServlet
public class TestServlet extends UtilFreemarkerServlet{
private static final long serialVersionUID = 1L;
private String website;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.service(req, resp);
boolean handleResult = handlerForRequest(req, resp);
}
protected boolean handlerForRequest(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (resp.getStatus() == 404) {
String pageNotFoundUrl = "http://localhost:10039/my.website/my/notfound.html";
RequestDispatcher rd = req.getRequestDispatcher(url);
rd.forward(req, resp);
// resp.sendRedirect(url);
}
return true;
}
}
Do a forward instead of a redirect to the wanted resource, and the URL will stay the same.
RequestDispatcher rd = request.getRequestDispatcher("my_404.html");
rd.forward(request, response);
RequestDispatcher is not useful in my case because the response has always been committed. Here is the solution I end up with for Freemarker Servlets;
I am overriding a couple of methods of Freemarker servlet for my purpose such as service() and requestUrlToTemplatePath(). By this way, I am able to interfere right before the response is committed.
First Override is for the service method. My purpose is to check if the requested url page exists or not.
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
checkIfPageExists(req);
super.service(req, resp);
}
checkIfPageTemplateExists checks if the template of the page is null or not. If null, then it means it is not available. In this case I set a request attribute. Otherwise, it means it exists.
protected void checkIfPageExists(HttpServletRequest req)
throws ServletException {
String relativeUrl = requestUrlToTemplatePath(req);
try {
getConfiguration().getTemplate(relativeUrl); //throws exception if the template cannot be accessed
} catch (TemplateNotFoundException e) {
logger.debug("TemplateNotFoundException for " + relativeUrl);
pageNotFound = "/customNotFoundPage.html";
} catch (IOException e) {
logger.debug("IOException for " + relativeUrl);
pageNotFound = "/customNotFoundPage.html";
}
req.setAttribute(NOT_FOUND_PAGE, pageNotFoundPage);
}
And the last line stated in bullet 1 is for super.service() method. This will trigger the requestUrlToTemplatePath() method which is actually the method you can specify what url page to be shown without changing the url.
I am just checking if the request has a NOT_FOUND_PAGE attribute. If so, just overwrite the path itself and move on to the next step in the flow. Otherwise, just use the path of super class.
#Override
protected String requestUrlToTemplatePath(HttpServletRequest request)
throws ServletException {
String path = super.requestUrlToTemplatePath(request);
//Check if NOT_FOUND_PAGE is requested
if(request.getAttribute(NOT_FOUND_PAGE) != null) {
path = (String) request.getAttribute(NOT_FOUND_PAGE);
}
return path;
}
I'm working on a website using JAVA Spring mvc. I have a functionality that requires two controllers. First of all, the request is handled by controller1 who redirect it to controller2 using a return new ModelAndView ("redirect:controller2.htm"). All is working fine. However,I would like to block the direct access to the controller2 ( block a call from the url "controller2.htm") because the controller2's form needs data from the controller1.I want that the only case in which controller2 is used is the redirection from controller1. I would like a solution without annotations.Thanks in advance for your help.
Here is the code :
Controller1:
public class controller1 extends SimpleFormController implements Serializable {
private PersonManager pManager ;
#Override
public ModelAndView onSubmit(Object command) {
CommandPerson cmd = (CommandPerson) command;
Person p = null;
String viewName = "redirect:controller2.htm";
try {
p = pManager.getPersonbyID(cmd.getID());
} catch (EmptyResultDataAccessException ex) {
viewName="NosuchPerson";
}
ModelAndView mav = new ModelAndView(viewName);
mav.addObject("ID",cmd.getID());
return mav;
}
controller2:
public class controller2 extends SimpleFormController implements Serializable {
private PersonManager pManager ;
#Override
public ModelAndView onSubmit (Object command) throws ServletException, IOException {
Person p = (Person) command;
Map<String,Object> model = new HashMap<String,Object>();
pManager.UpdatePerson(p);
model.put("person", p);
return new ModelAndView("SuccesfulUpdate","model",model);
}
protected Object formBackingObject(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("ID");
if(id==null) {
response.sendRedirect("controller1.htm");
return null;
} else{
Personne p = pManager.getPersonbyID(id);
return p;
}}
If the url "controller2.htm" is called directly the ID parameter will be null,and as the formBackingObject() is the first method executed when the request is being handled I thought I could make a redirection in it , but it didn't work as I'm redirected to the controller2's form being empty.
Your problem is very near to the Cross Site Request Forgery protection, so the same general solution should apply.
You just have to generate a random token in Controller1, put it in model under an arbitrary name (say "_csrf") and also store its value in session. Then in Controller2 you test that :
the parameter request _csrf is present in request
it is equal to the value stored in session
and immediately remove the _csrf value from the session.
If both requirements are met, it is highly probable that Controller2 was called via a redirect from Controller1, as nobody else should be able to guess the value
I finally found the solution. I overrided the showForm method . In this method , I could test if the parameter exists in the request . If it exists the formBackingObject method is called and the controller2's form is displayed else there is a redirection to controller1.
Controller1:
public class controller1 extends SimpleFormController implements Serializable {
private PersonManager pManager ;
#Override
public ModelAndView onSubmit(Object command) {
CommandPerson cmd = (CommandPerson) command;
Person p = null;
String viewName = "redirect:controller2.htm";
try {
p = pManager.getPersonbyID(cmd.getID());
} catch (EmptyResultDataAccessException ex) {
viewName="NosuchPerson";
}
ModelAndView mav = new ModelAndView(viewName);
mav.addObject("ID",cmd.getID());
return mav;
}
Controller2:
public class controller2 extends SimpleFormController implements Serializable {
private PersonManager pManager ;
#Override
public ModelAndView onSubmit (Object command) throws ServletException, IOException {
Person p = (Person) command;
Map<String,Object> model = new HashMap<String,Object>();
pManager.UpdatePerson(p);
model.put("person", p);
return new ModelAndView("SuccesfulUpdate","model",model);
}
protected Object formBackingObject(HttpServletRequest request,HttpServletResponse response)
throws ServletException, IOException {
String id = request.getParameter("ID");
if(id==null) {
response.sendRedirect("controller1.htm");
return null;
} else{
Personne p = pManager.getPersonbyID(id);
return p;
}}
protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors)throws Exception {
String id = request.getParameter("ID");
if (id==null) return new ModelAndView("redirect:controller1.htm");
else{
Personn p = (Personne) formBackingObject(request, response);
return new ModelAndView("UpdatePersonForm","Person",p);
}}
something awful is happening
i have 2 servlets in my project - one of them simply has a post method and is responsible for handling file uploads. i recently added the other one - it has a get and a post method.
here is the 2nd servlet code
#Singleton
#WebServlet("/Medical_Web")
public class XXXDetailsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject
private Provider<XXXPersistenceManager> persistenceManager;
#Inject
private Provider<XXXChain> chainProvider;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("servlet address = " + this);
final String xxx= request.getParameter("xxx");
String json = "";
try {
final XXXBean xxxBean = persistenceManager.get().find(xxx);
json = new GsonBuilder().create().toJson(xxxBean);
} catch (Exception ex) {
ex.printStackTrace();
}
request.setAttribute("json", json.trim());
getServletContext().getRequestDispatcher("/XXX.jsp").forward(request, response);
}
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("servlet address = " + this);
final String xxx = request.getParameter("xxx");
try {
final XXXChain chain = chainProvider.get();
chain.getContext().setAttribute(XXX_TYPE, XXXType.DELETE);
final XXXBean xxxBean = persistenceManager.get().find(xxx);
final List<XXXBean> xxxList = new ArrayList<XXXBean>();
xxxList.add(xxxBean);
chain.process(xxxList);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
now - here's whats getting me
for some reason - even though this is marked as a #Singleton - the servlet addresses are definitely coming back as different. I noticed this initially when I hit a null pointer in my post method - whenever i call the get method, the instance of the servlet i get back has all the fields populated. whenever i call the post method, the instance of the servlet i get back (it is a different instance) does not have the fields populated (just null, seems like they didn't get injected).
I'm really struggling to figure out what's going on here. it seems as if an instance of this servlet was created outside of the guice context. if it matters - we are using JBoss 7.1
(sorry about all the XXX's, don't know if i can post actual names)
here's the rest of my guice setup
public class XXXServletContextListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new XXXUploadModule(), new XXXServletModule());
}
}
and here's the servlet module
public class XXXServletModule extends ServletModule {
#Override
protected void configureServlets() {
serve("/xxx1").with(XXXDetailsServlet.class); // this one fails on post
serve("/xxx2").with(XXXUploadServlet.class); // this one works
}
}
I am not familiar with how Guice servlet integration works, but having the #WebServlet("/Medical_Web") annotation means that your web container will also instantiate that servlet to serve requests. A pool of them actually, it doesn't have a concept of singletons.
My guess is you just have to remove the annotation and let ServletModule control the servlet life-cycle.