Kohei Nozaki's blog 

Doesn't InitialContext.doLookup() bring resource leak?


Posted on Thursday Feb 12, 2015 at 12:00PM in Technology


There’s a convenient static method called InitialContext.doLookup() which introduced at Java6. it uses Generics so we don’t need to cast returned object by hand. implementation is very simple as follows:

public static <T> T doLookup(String name) throws NamingException {
    return (T) (new InitialContext()).lookup(name);
}

I think it’s bad because there’s no way to invoke InitialContext#close() because doLookup() doesn’t save the reference to InitialContext instance anywhere. if it acquired some resource such as TCP socket it may brings resource leak.

Personally I will avoid use of doLookup() because of this reason while there are many opinion that it doesn’t need to close explicitly at most of environments. I guess I’m too sensitive about it but I have a history of strugging with leak of JDBC resources (Connection, Statement and ResultSet) so I’m very curious about this kind of problem.

Sometimes handling of InitialContext is annoying because it should be keep opened during use of returned instance on some environments or implementations. also I wonder why InitialContext doesn’t implemented AutoCloseable while it’s a perfect candidate for it.

For Servlets you could write as follows:

public class TestServlet extends HttpServlet {

    private Context context;
    private DataSource dataSource;

    @Override
    public void init() throws ServletException {
        try {
            context = new InitialContext();
            dataSource = (DataSource) context.lookup("java:comp/env/jdbc/derby");
        } catch (NamingException e) {
            throw new ServletException(e);
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try (Connection cn = dataSource.getConnection()) {
        	// database operations
        } catch (SQLException e) {
            throw new ServletException(e);
        }
    }

    @Override
    public void destroy() {
        if (context != null) {
            try {
                context.close();
            } catch (NamingException e) {
                // no-op
            }
        }
    }
}

In jberetweb, I wrote an interface named JobOperatorWork and a method intended to use with it called doWorkWithJobOperator() for ease of handling of InitialContext closing.

In Java EE environment, you could simply use @Resource or @EJB for avoiding annoying procedure of closing.


jconsole.sh in WildFly 8.2.0.Final doesn't work


Posted on Thursday Feb 12, 2015 at 10:06AM in Technology


Environment

  • WildFly 8.2.0.Final

Problem

A shell script $WILDFLY_HOME/bin/jconsole.sh is shipped with WildFly to launch JConsole with an additional jar to connect to WildFly instance, but it doesn’t work. as reported in this issue, it made wrong classpath.

Workaround

Launch $JAVA_HOME/bin/jconsole directly instead with an additional parameter as follows:

jconsole -J-Djava.class.path=$JAVA_HOME/lib/jconsole.jar:$JAVA_HOME/lib/tools.jar:/Users/kyle/servers/wildfly-8.2.0.Final/bin/client/jboss-cli-client.jar


Defining Embedded Derby as a DataSource of Tomcat 8


Posted on Wednesday Feb 11, 2015 at 12:16AM in Technology


Configuration

  1. Put derby.jar into $CATALINA_HOME/lib

  2. Define a Resource element inside Context element in $CATALINA_HOME/conf/context.xml as follows:

    <Resource name="jdbc/derby" auth="Container"
    		  driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
    		  username="sa" password="sa"
    		  type="javax.sql.DataSource"
    		  url="jdbc:derby:/Users/kyle/tmp/sampledb;create=true"/>
  3. Clone derby-shutdown-listener, exec mvn clean package and put target/derby-shutdown-listener.jar into $CATALINA_HOME/lib

  4. Put following fragment into Server element in $CATALINA_HOME/conf/server.xml

    <Listener className="org.nailedtothex.derby.DerbyShutdownLifecycleListener" />

Test of lookup from Servlet

  1. Put following fragment into WEB-INF/web.xml of your web application

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
        <resource-ref>
            <res-ref-name>jdbc/derby</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
    </web-app>
  2. Put an example Servlet as follows

    @WebServlet(urlPatterns = "/")
    public class TestServlet extends HttpServlet {
    
        private Context context;
        private DataSource dataSource;
    
        @Override
        public void init() throws ServletException {
            try {
                context = new InitialContext();
                dataSource = (DataSource) context.lookup("java:comp/env/jdbc/derby");
            } catch (NamingException e) {
                throw new ServletException(e);
            }
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            try (Connection cn = dataSource.getConnection();
                 Statement st = cn.createStatement();
                 ResultSet rs = st.executeQuery("SELECT CURRENT_TIMESTAMP FROM SYSIBM.SYSDUMMY1")) {
                while (rs.next()) {
                    resp.getWriter().write(rs.getTimestamp(1).toString());
                }
            } catch (SQLException e) {
                throw new ServletException(e);
            }
        }
    
        @Override
        public void destroy() {
            if (context != null) {
                try {
                    context.close();
                } catch (NamingException e) {
                    // no-op
                }
            }
        }
    }
  3. Access from your browser


Complex string replacing on Java


Posted on Tuesday Feb 10, 2015 at 10:06PM in Technology


Sometimes annoying requirement of string replacing will risen. everytime I forgotten how to do it so I leave this as my note. also there’s a JUnit test case.

Requirement

Assume we have following string literals. we have to convert input string to expected.

String input = "<li><a href=\"../../jbatch/hello/\" >anchor</a></li>";
String expected = "<li><a href=\"/entry/articles-jbatch-hello\" >anchor</a></li>";

Solutions

Using numbered groups

Pattern p = Pattern.compile("(<a href=\")\\.\\./\\.\\./(.*)/(.*)/\"");
Matcher matcher = p.matcher(input);
String result = matcher.replaceAll("$1/entry/articles-$2-$3\"");

Using named groups

Pattern p = Pattern.compile("(?<prefix><a href=\")\\.\\./\\.\\./(?<category>.*)/(?<handle>.*)/\"");
Matcher matcher = p.matcher(input);
String result = matcher.replaceAll("${prefix}/entry/articles-${category}-${handle}\"");

Using Matcher#appendReplacement(). this one is most flexible.

Pattern p = Pattern.compile("(?<prefix><a href=\")(?<url>.*)\"");
Matcher matcher = p.matcher(input);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
	// any complex logic can be placed here
	String url = matcher.group("url");
	String[] urls = url.split("/");
	matcher.appendReplacement(sb, "${prefix}/entry/articles-" + urls[2] + "-" + urls[3] + "\"");
}
matcher.appendTail(sb);
String result = sb.toString();

Escaping special character for replacement

$ have special meaning for replacement string, but sometimes we may need to use $ as just a literal. for such case, we can use Matcher.quoteReplacement() for escaping $ character as follows:

String input = "../../jbatch/hello/";
String expected = "../../$1/${name}/";
Pattern p = Pattern.compile("(?<prefix>\\.\\./\\.\\.)/.*/.*/");
String result = p.matcher(input).replaceAll("${prefix}/" + Matcher.quoteReplacement("$1/${name}") + "/");


Enabling SSL for Apache/WildFly


Posted on Monday Feb 09, 2015 at 05:56PM in Technology


Environment

  • WildFly 8.2.0.Final

  • httpd-2.2.15-39.el6.centos.x86_64

  • CentOS 6.5

  • public.crt: begins with BEGIN CERTIFICATE

  • intermediate.crt: begins with BEGIN CERTIFICATE

  • private.key: begins with BEGIN RSA PRIVATE KEY

Edit /etc/httpd/conf.d/ssl.conf

SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCertificateFile /usr/local/ssl/public.crt
SSLCertificateKeyFile /usr/local/ssl/private.key
SSLCertificateChainFile /usr/local/ssl/intermediate.crt
SSLPassPhraseDialog exec:/usr/local/ssl/passphrase.sh

Put passphrase.sh

#!/bin/sh
echo "put the passphrase here"

Define an ajp-listener

Execute following command with jboss-cli:

/socket-binding-group=standard-sockets/socket-binding=https-external:add(port=443)
/subsystem=undertow/server=default-server/ajp-listener=myListener:add(socket-binding=ajp, redirect-socket="https-external", enabled=true)

Put /etc/httpd/conf.d/jk.conf

<VirtualHost *:80>
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / http://www.example.org/
</VirtualHost>

Put following inside VirtualHost element of /etc/httpd/conf.d/ssl.conf

ProxyPass / ajp://localhost:8009/
ProxyPassReverse / https://www.example.org/