I've got a pretty straightforward Java webapp that has been showing some very strange behavior on development systems. The problem starts with the registration handler, which is implented as follows:
//XXX: this shouldn't really be 'synchronized', but I've declared it as such
// for the sake of debugging this issue
public synchronized ModelAndView submitRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String email = request.getParameter("email");
String pass = request.getParameter("pass");
String conf = request.getParameter("conf");
String name = request.getParameter("name");
EntityManager em = DatabaseUtil.getEntityManager(request);
//[make sure required fields are present and valid, etc.]
User user = getUserForEmail(email, em);
if (user != null) {
//[user already exists, go to error page]
}
//create the new user
em.getTransaction().begin();
try {
user = new User();
//[set fields, etc.]
em.persist(user);
//[generate e-mail message contents]
boolean validEmail = EmailUtility.sendEmail(admin, recip, subject, message, null, recip);
if (validEmail) {
em.getTransaction().commit();
//[go to 'registration successful' page]
}
em.getTransaction().rollback();
//[go to error page]
}
catch (Exception e) {
em.getTransaction().rollback();
//[go to error page]
}
}
The problem occurs on the EmailUtility.sendEmail() call. The code for this method is pretty straightforward:
public static boolean sendEmail(String fromAddress, String to, String subject, String message, String fromHeaderValue, String toHeaderValue) {
try {
Session session = getMailSession(to);
Message mailMessage = new MimeMessage(session);
mailMessage.setFrom(new InternetAddress(fromAddress));
if (fromHeaderValue != null) {
mailMessage.setHeader("From", fromHeaderValue);
}
if (toHeaderValue != null) {
mailMessage.setHeader("To", toHeaderValue);
}
mailMessage.setHeader("Date", new Date().toString());
mailMessage.setRecipients(RecipientType.TO, InternetAddress.parse(to, false));
mailMessage.setSubject(subject);
mailMessage.setContent(message, "text/html;charset=UTF-8");
Transport.send(mailMessage);
return true;
} catch (Throwable e) {
LOG.error("Failed to send e-mail!", e);
return false;
}
}
What happens is that when the code reaches the call for EmailUtility.sendEmail(), instead of calling that method execution recurses through submitRegister(). That's easily one of the most bizarre things I've ever seen.
For awhile I didn't even believe that was what's actually happening; but at this point I've confirmed it by synchronizing the method involved and adding print statements on every line of both methods. submitRegister() recurses, and sendEmail() is never called. I've got no idea how this is even possible.
Frustratingly, the exact same code runs just as it should on the production server. It's only on development systems that this problem appears.
Any suggestions regarding what might be causing this problem and what I can do to fix it are welcome.
You are right, This is not possible :)
I would suggest you strip away all other code, put in a lot of logging, if you don't like debugging and see what happens. Start with something like:
public synchronized ModelAndView submitRegister(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
LOG.debug("submitRegister: " + this.toString);
EmailUtility.sendEmail("a#x.y", "b#x.y", "subject", "message", "from", "to");
}
public static boolean sendEmail(String fromAddress, String to, String subject, String message, String fromHeaderValue, String toHeaderValue) {
LOG.debug("sendEmail: " + this.toString());
}
The toString will show you what classes are involved.
My guess would be that:
your first call fails, so sendEmail will never be invoked
submitRegister is triggered more than once by someone else, not by the EmailUtility.sendEmail statement.
If you get the stripped version to work, start putting back your code, one peace at a time to see where it all goes bad :)
Okay, I tracked this down to a few different issues working together:
On development systems, the classpath was missing javax.mail.Address. This caused the EmailUtility class to fail to initialize, and would throw a NoClassDefFoundError on the sendEmail() call, before any code from that method could execute.
The code in submitRegister() had a catch Exception block, but NoClassDefFoundError extends Error, not Exception. So it bypassed the catch Exception block entirely.
The Spring controller where the Error was actually caught had some of the most questionable "error-handling" code I've ever come across:
try {
Method serviceMethod = this.getControllerClass().getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
if (this.doesMethodHaveAnnotation(serviceMethod, SynchronizedPerAccount.class)) {
synchronized(this.getAccountLock(request)) {
super.doService(request, response);
}
}
else {
//don't need to execute synchronously
super.doService(request, response);
}
}
catch (Throwable ignored) {
super.doService(request, response);
}
So the NoClassDefFoundError was propagating back up to the Spring controller, which was catching it and attempting to re-invoke the doService() method, which caused submitRegister() to be invoked again. It wasn't recursion (though there was no way to tell that by just looking at the debug output), it was the Spring controller calling it twice for the same request. It never got called more than twice for a given request, because there's no try/catch around the second doService() call.
Long story short, I patched up these issues and problem solved.
Related
There is an implemented method of the AbstractRegueestLoggingFilter class called afterRegueest. It has two parameters: HttpServletRequest request, String message. For some reason, the message parameter comes incomplete, that is, cut off (there is a feeling that this message has a dimension, as is often the case with the size of varhar in the database). I don't understand how this can happen.
P.S. the message should display the information on the request that the client asks for. For example Put: /api/url and further the request body. I use it for logging.
So the body itself is cut off, and already at the input in the parameter.
How can I fix this problem?
#Override
#SuppressWarnings("NullableProblems")
protected void afterRequest(HttpServletRequest request, String message) { // Here it is already incomplete !!!!!
if (!FORBIDDEN_URLS.contains(request.getRequestURI())) {
ApiRequestLog log = new ApiRequestLog();
log.setMethod(RequestMethod.valueOf(request.getMethod()).name());
log.setUrl(request.getRequestURL().toString());
log.setParams(request.getQueryString());
String body = StringUtils.substringAfter(message, "payload=");
if (StringUtils.isNotBlank(body)) {
log.setBody(body);
}
try {
log.setCreatedBy(UserHelper.getUser());
} catch (RuntimeException ignored) {
}
try {
queueService.sendToQueue(log, REQUESTS_FOR_SAVE);
} catch (JMSException ignored) {
}
}
}
The problem was that we manually wrote into the code the maximum length of the request body that we could accept. In this regard, I just changed the maximum number of characters to a larger value.
#Autowired
public CustomLoggingFilter(QueueService queueService) {
setIncludePayload(true);
setMaxPayloadLength(2048);
setBeforeMessagePrefix("");
setBeforeMessageSuffix("");
setAfterMessagePrefix("");
setAfterMessageSuffix("");
this.queueService = queueService;
}
I change setMaxPayloadLength(2048) on 1million length value.
I'm using SparkJava and it seems that exceptions thrown in routes are not showing up in console unless I explicitly catch them.
For example, given
Spark.post("/lookup", this::lookup);
and
private String lookup(Request req, Response res) {
// some stuff
return json.toString();
}
If // some stuff throws an exception, nothing appears in console. But if I explicitly catch and print the exception, it prints it to console as expected.
private String lookup(Request req, Response res) {
try {
// some stuff
} catch(Exception e) {e.printStackTrace();}
return json.toString();
}
This leads me to believe that somewhere further up in the route callstack, all exceptions are caught and hidden.
As you can imagine, this behavior results in some rather frustrating debugging. Is there any way to make it so that all exceptions are always shown in console?
In your Main class, before any routes, add this:
exception(Exception.class, (exception, request, response) -> {
exception.printStackTrace();
});
Any exception not otherwise caught by your application code will now be dumped to the console.
(IMO Spark should do this by default...)
I am trying to output the rendering of a JSP page using RequestDispatcher.include() in the following method:
public static String readTemplate(HttpServletRequest request, HttpServletResponse response, String template) {
HttpServletResponseWrapper responseWrapper = new HttpServletResponseWrapper(response) {
private final StringWriter sw = new StringWriter();
#Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
#Override
public String toString() {
return sw.toString();
}
};
String templateFile = "/templates/" + template + ".jsp";
logger.log(Level.INFO, "Reading template {0} ...", templateFile);
try {
request.getRequestDispatcher(templateFile).include(request, responseWrapper);
} catch (ServletException | IOException | IllegalStateException e) {
logger.log(Level.SEVERE, e.getMessage());
}
logger.log(Level.INFO, "Completed reading template {0}", templateFile);
// retrieve HTML from response
return responseWrapper.toString();
}
The method is part of a servlet I am running with Tomcat8. This works perfectly the first time, but hangs at the include call the second run (i.e. if I click refresh on the browser).
I have already verified the dispatcher is not null.
This is what I can see from the catalina.log (cleaned for your review)
First run:
26-Feb-2015 17:41:17.921 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
26-Feb-2015 17:41:18.046 INFO [http-nio-8081-exec-2] ism.Reports.readTemplate Completed reading template /templates/INCIDENT_REPORT.jsp
Second run (response never returns, i.e. browser always loading page):
26-Feb-2015 17:41:26.327 INFO [http-nio-8081-exec-8] ism.Reports.readTemplate Reading template /templates/INCIDENT_REPORT.jsp ...
This does not change until I reboot Tomcat.
Can someone explain what am I doing wrong or at least how to debug this? Thanks!
EDIT 1: Forgot to say the method is static, but I also tried making it not static didn't make any difference
The code above is working, I realized where the issue was. The included JSP page was opening many MySQL connections but only one was closed. Hence the second request was waiting for the MYSQL resources to be freed before performing the task. I am very sorry I didn't notice this until now, and I didn't even mention MySQL connections in the first place. I guess not receiving replies here lead me to find the solution on the JSP file itself.
How can I retrieve a compile time error message from StringTemplate as a String?
This code for instance:
STGroup stg = new STGroup('<', '>');
CompiledST compiledTemplate = stg.defineTemplate("receipt", "<an invalid template<>");
if (compiledTemplate == null)
System.out.println("Template is invalid");
Will simply log something like "invalid came as a complete surprise to me", but I want to display this error message in my UI.
I can access the ErrorManager with stg.errMgr. I expected a method like getErrors() here, but there isn't...
You could set an error listener for the group, which would allow you to catch the error, and then pass it to the UI from there.
This answer tells you more about implementing an STErrorListener. The example they give doesn't compile since they're throwing checked exceptions from within the ErrorListener. Perhaps a better approach would be to handle the errors directly inside the listener, or you could just throw a RuntimeException so you could catch the errors when you call stg.defineTemplate(...).
public class MySTErrorListener implements STErrorListener {
...
#Override
public void compileTimeError(STMessage msg) {
// do something useful here, or throw new RuntimeException(msg.toString())
}
...
}
If you were to throw the RuntimeException you could then catch it when you define the ST:
stg.setListener(new MySTErrorListener());
try{
CompiledST compiledTemplate = stg.defineTemplate("receipt", "<an invalid template<>");
} catch (Exception e)
{
// tell the UI about the error
}
I'm using google-oauth-java and one thing that really complicates my life is that when I attempt using OAuthClient.invoke() I frequently get OAuthProblemException thrown due to request returning code 302 instead of 200. Because of that I found myself rewriting invoke code and usingOAuthClient.access() instead. I'm wondering if I'm missing some type of followRedirect setting? The documentation is non-existing and examples don't really help, can someone help me here?
Here's snippet from OAuthClient to illustrate
public OAuthMessage invoke(OAuthMessage request, ParameterStyle style)
throws IOException, OAuthException {
OAuthResponseMessage response = access(request, style);
if ((response.getHttpResponse().getStatusCode() / 100) != 2) {
OAuthProblemException problem = response.toOAuthProblemException();
try {
problem.setParameter(OAuthProblemException.SIGNATURE_BASE_STRING,
OAuthSignatureMethod.getBaseString(request));
} catch (Exception ignored) {
}
throw problem;
}
return response;
}
Since I dealt with this by using OAuthClient.access() and nobody is coming forward I'm going to accept my own solution