22 March 2015

Guava

In Verify.verify’s error message, only %s is supported.

Logging

Log4j

In 1.2, %d{ISO8601} means the format yyyy-MM-dd HH:mm:ss,SSS which is wrong. The correct format is yyyy-MM-ddTHH:mm:ss,SSS as specified by wikipedia ISO 8601 page. 2.x is in consistent with wikipedia.

Without configuration file, lo4j 1.x emits the following message to stdout and no log4j log messages are printed:

log4j:WARN No appenders could be found for logger (language.Log4jLogger).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Without configuration file, log4j 1.x with slf4j emit the following message to stdout and no log4j log messages are printed:

log4j:WARN No appenders could be found for logger (language.Slf4jLogger).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

Without configuration file, log4j 2.x emits the following message to stdout and log4j log messages are printed to stdout:

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.
19:50:47.889 [main] ERROR com.rainbow.LoggerTest - info message

Logback with slf4j

Without configuration file, logback log message are printed to stdout. For details, refer to Chapter 3: Logback configuration.

JSON

Netty

Colorful Terminal

Build

Maven

To download a package without a POM file:

mvn dependency:get -DgroupId=org.apache.kafka -DartifactId=kafka-clients -Dversion=0.9.0.0

Note that the above command can’t be used to download Javadoc jar or source

jar for a package.

Download Javadoc Jar:

mvn dependency:resolve -Dclassifier=javadoc

Download source jar:

mvn dependency:sources

For details, refer to:

Gradle

Gretty:

In different environments, Gradle may execute a set of test cases in different orders. For example, there are test cases A and B. In environment 1, the execution order is A -> B. In environment 2, the execution order is B -> A. Test case failures related to such kind of execution order are hard to be fixed.

Gradle eclipse task downloads source jars by default.

JVM

Scala

  • Download Scala documentation from http://www.scala-lang.org/files/archive/

Web App

RequestDispatcher is confusing. But Introduction to Request Dispatcher explains it well.

classes places in src/test/java are not loaded by gradle jettyRun.

Error Handling in Web App

  • If no customized error handling is provided, the default error page provided by the container such as Tomcat is returned. The error page usually contains Java exception stack trace. HTTP response is a error page with a HTTP status 500.
  • Customized error handling usually return a HTTP response with status code 302. The browser will then go to the URL contained in Location header. So there are two HTTP responses: one with status code 302 and one with status code 200.

One way to do customized error handling is to use a Filter to catch the exception and does the redirect with HttpServletResponse.sendRedirect. Such a filter catches the exceptions thrown by the application code and the exceptions thrown by Web framework code. If Spring framework is used, a @ControllerAdvice which has some methods annotated with @ExceptionHandler can also be used. But such a controller advice can only catch exceptions thrown by a web controller.

404 Not Found Handling in Web App

Approaches:

  • Web container returns a 404 page by default. Only one HTTP response is produced.
  • Web container returns a customized 404 page. Only one HTTP response is produced. github.com uses this approach.
  • Web container returns a HTTP 302 response. Browser redirects to the Location header in the response. Two HTTP responses are produced: one HTTP 302 and one HTTP 200.

Servlet

The following conclusion is verified with gradle jettyRun. Filters are initialized before servlets. Unlike servlets which can be lazily initialized, filters are always initialized when the servlet contains starts up.

ORM

Tomcat

Spring

  • [Spring 3 MVC accessing HttpRequest from controller] (http://stackoverflow.com/questions/8504258/spring-3-mvc-accessing-httprequest-from-controller)
  • [how to get getServletContext() in spring mvc Controller] (http://stackoverflow.com/questions/26923907/how-to-get-getservletcontext-in-spring-mvc-controller)

Qualifier

Create the following three classes in a package which is component scaned.

@Service
public class Wife {
  public Wife() {
    System.out.println("construct a wife");
  }
}
@Service
public class Husband {
  public Husband() {
    System.out.println("construct a husband");
  }
}
@Service
public class Couple {

  @Autowired(required = true)
  public Couple(@Qualifier("husband") Husband husband, @Qualifier("wife") Wife wife) {
    System.out.println("construct a couple");
  }
}

A test case which knows how to load application context:

public class CoupleTest extends AbstractContextTest {
  @Autowired
  private Couple couple;
  
  @Test
  public void testConstruct() {
    System.out.println(couple);
  }
}

Running the test case produces:

construct a wife
construct a husband
construct a couple
com.rainbow.service.Couple@733c423e

MVC

If an interceptor’s preHandle method returns false for a HTTP GET, a response with status code 200 and an empty body may be returned.

Magic

  • spittleList for List<Spittle> for model name
  • In web.xml, a serlvet named as appServlet’s context is WEB-INF/appServlet-context.xml.
  • In a application context xml file, the / in <import resource="classpath:/service-config.xml" /> is optional. The reason is that ClassPathResource.ClassPathResource(String path) ignores it.
  • supportedMediaTypes in HttpMessageConverter can be used to set HTTP response’s Content-Type header. produces = MediaType.APPLICATION_JSON_VALUE overrides it.

REST

Allow CORS

Add the following text to web.xml:

  <!-- CORS -->
  <filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.rainbow.CorsFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/rest/*</url-pattern>
  </filter-mapping>

CorsFilter:

package com.rainbow;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
 * Filter to allow CORS rest API calls.
 */
public class CorsFilter implements Filter {

  @Override
  public void doFilter(ServletRequest req, ServletResponse resp,
      FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) resp;

    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods",
                       "POST, GET, OPTIONS, DELETE");
    response.setHeader("Access-Control-Max-Age", "3600"); // seconds
    response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");

    chain.doFilter(req, resp);
  }

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void destroy() {}
}

JDBC

Before Java 7:

Connection conn = ...;
try {
  // SQL statements
  conn.commit(); 
} catch (Throwable t) {
  if (conn != null) conn.rollback();
} finally {
  if (conn != null) conn.close();
  }
}

Java 7 and above:

try (Connection conn = ...;) {
  conn.commit();
} 

The above code works only if Connection.close method does rollback if conn.commit() is not executed. Java 8 Connection.close method’s Javadoc discourages this way.

And remember to always invoke Connection.close() to release database resources. If a thrown exception causes Java process to terminate, the OS will terminate the Java process’s TCP connection to the remote database server. The database server can release related resources. The related database resources will not be released for the following cases:

  • The exception is swallowed or the
  • Network cable is unplugged suddenly. In this case, the OS hosting Java process does not have a change to send more TCP packages to do a graceful TCP close with the remote database server.

Be careful with JDBC url in Java code. Some unrecognized options are ignored silently. If the JDBC url is given literally in XML, & needs to be escaped. If the JDBC url is given in a properties file, don’t escape it.

Performance Tuning

Web Application Development

Not need to close input stream for HTTP request. See Is is necessary to close the input stream returned from HttpServletRequest?. Not need to close output stream for HTTP response. See Should one call .close() on HttpServletResponse.getOutputStream()/.getWriter()?.

MISC