9/29/2006

Inject EntityManagerFactory and EntityManagerFactory to Servlet

You can inject EntityManagerFactory and/or EntityManager into a Servlet, but be aware of the thread-safe issue. A servlet can service multiple concurrent requests using multiple threads. So all instance variables are shared by all these threads, which may cause undesired side-effect.

The good news is, all methods in EntityManagerFactory interface are thread-safe. Therefore, you can safely inject EntityManagerFactory into a servlet instance variable.

public class MyServlet extends HttpServlet {
//this is thread-safe
@PersistenceUnit(unitName="my-pu")
private EntityManagerFactory emf;
However, methods in EntityManager interface are not thread-safe, and may not be shared among multiple concurrent requests. Therefore, do not inject EntityManager into a servlet instance variable.
//this is not thread-safe, and avoid it
@PersistenceContext(unitName="my-pu")
private EntityManager em;
Having said that, you can still inject EntityManager at the servlet class type level, and look it up when needed during request processing.
@PersistenceContext(unitName="my-pu", name="persistence/em")
public class MyServlet extends HttpServlet {
protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
try {
InitialContext ic = new InitialContext();
EntityManager em =
(EntityManager) ic.lookup("java:comp/env/persistence/em");
} catch (NamingException ex) {
...
}
}
}

9/22/2006

Resource Injection in Servlet Filter

You can inject EJB or resources into servlet filters, in the same way as injecting into servlet classes. Things that can be injected include EJB 3 stateless and stateful session beans, EJB 2.1 Home, DataSource, ORB, UserTransaction, javamail session, JMS ConnectionFactory, JMS Queue, JMS Topic, etc. For example,

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 java.io.IOException;
import java.io.PrintWriter;
import javax.ejb.EJB;
import javax.annotation.Resource;
import javax.sql.DataSource;

public class MyServletFilter implements Filter {
@EJB(beanName="HelloBean")
private HelloRemote helloBean;

@Resource(mappedName="jdbc/__default")
private DataSource ds;

private FilterConfig filterConfig;

public void doFilter(ServletRequest request,
ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
PrintWriter pw = response.getWriter();
helloBean.hello();

try {
chain.doFilter(request, response);
} catch(RuntimeException e) {
throw e;
} catch(Exception e) {
throw new ServletException(e);
}
}
public void destroy() {
}

public void init(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
}

9/20/2006

Default JNDI Name for Resource or EJB Injection

When a resource or EJB reference is injected to a component class, not only can you directly use this variable, you can also lookup with JNDI. For example,

package demo;
public class FooServlet extends HttpServlet {
@Resource(name="jdbc/mysql-ds")
private DataSource dataSource;

protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Connection con = null;
Connection conn = null;
try {
InitialContext ic = new InitialContext();
DataSource ds =
(DataSource) ic.lookup("java:comp/env/jdbc/mysql-ds");

//the following 2 statements work the same:
conn = dataSource.getConnection();
con = ds.getConnection();
} catch (NamingException ex) {
throw new ServletException(ex);
} catch (SQLException ex) {
throw new ServletException(ex);
} finally {
//close con conn here
}
}
}
If the name() field is not specified for @EJB or @Resource, the default jndi name is not the variable name; instead, it's in the form of fully-qualified-classname/variable-name. Therefore, using default jndi name, the above example needs to be rewrite as follows:
package demo;
public class FooServlet extends HttpServlet {
@Resource
private DataSource dataSource;

protected void doGet(
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Connection con = null;
Connection conn = null;
try {
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup(
"java:comp/env/demo.FooServlet/dataSource");

//the following 2 statements work the same:
conn = dataSource.getConnection();
con = ds.getConnection();
} catch (NamingException ex) {
throw new ServletException(ex);
} catch (SQLException ex) {
throw new ServletException(ex);
} finally {
//close con conn here
}
}
}

9/15/2006

Reverse a String with StringBuilder or StringBuffer

Both StringBuilder and StringBuffer class have a reverse method. They work pretty much the same, except that methods in StringBuilder are not synchronized. This is the signature of StringBuilder.reverse:

public StringBuilder reverse()
This method returns an instance of StringBuilder. The interesting thing is, the returned value is actually itself. So what this method does is, it reverses itself and returns itself. This is the source code for StringBuilder.reverse:
public StringBuilder reverse() {
super.reverse();
return this;
}
In the following example, the old and the reversed string will print the same content after calling reverse method:
public static void main(String[] args) {
StringBuilder old = new StringBuilder(args[0]);
StringBuilder newsb = old.reverse();
System.out.println("original string: " + old);
System.out.println("new string: " + newsb);
}
If you still need to access the original content of the StringBuilder, you will need to save it to string before invoking sb.reverse().

9/12/2006

System getenv() reinstated in JDK 1.5

In this previous post, I wrote about using System.getenv(key) to get OS environment variable. Actually, System.getenv(key) is not new. It was introduced at the very beginning of JDK, deprecated in JDK 1.2, and reinstated in JDK 1.5 (aka JDK 5).

The reason why it was deprecated, according to JDK 1.3 javadoc:

Deprecated. The preferred way to extract system-dependent information is the system properties of the java.lang.System.getProperty methods and the corresponding getTypeName methods of the Boolean, Integer, and Long primitive types.
Then bug 4199068 was submitted shortly after, requesting this method to be reinstated. Due to popular demand, this method was eventually reinstated in JDK 1.5.
Tags: , ,

9/08/2006

Is a String Empty?

Prior to JDK 6, we can check if a string is empty in 2 ways:

  • if(s != null && s.length() == 0)
  • if(("").equals(s))
Checking its length is more readable and may be a little faster. Starting from JDK 6, String class has a new convenience method isEmpty():
boolean isEmpty()
Returns true if, and only if, length() is 0.
It is just a shorthand for checking length. Of course, if the String is null, you will still get NullPointerException. I don't see much value in adding this convenience method. Instead, I'd like to see a static utility method that also handle null value:
public static boolean notEmpty(String s) {
return (s != null && s.length() > 0);
}

9/03/2006

A Bad Way of Getting Java System Property

I don't like code like this:

String flag1 = System.getProperties().getProperty("flag1.key");
String flag2 = System.getProperties().getProperty("flag2.key");
Why not just call System.getProperty("flag1.key")? In most cases, the two produces the same result. But the former is unnecessarily verbose.

You may be able to save some security check overhead by caching the system properties inside your application, if you need to get a series of properties, and if SecurityManager is enabled. For example,
Properties sysProps = System.getProperties();
String flag1 = sysProps.getProperty("flag1.key");
String flag2 = sysProps.getProperty("flag2.key");
...
The security check is only performed once in the above block. But it requires both read and write permission on all system properties: permission java.util.PropertyPermission "*", "read,write";

With System.getProperty("key"), security check is performed for every call. But it only requires read permission on the target property: permission java.util.PropertyPermission "key", "read";

The savings may be negligible, if any. The only time I will use System.getProperties() is when the property key is unknown, and the application needs to iterate through all system properties based on some criteria. For example,
Properties myProps = new Properties();
Properties sysProps = System.getProperties();
Set<Map.Entry<String, String>> entrySet =
sysProps.entrySet();
while(entrySet.hasNext()) {
Map.Entry entry = entrySet.next();
String key = entry.getKey();
if(key.startsWith("foo.")) {
myProps.setProperty(key, entry.getValue(key));
}
}