Tutorials and What's HOT 

Configuring Tomcat 7 to Accept Maven's Structure

by budi kurniawan


Posted on Saturday Jan 09, 2016 at 02:52PM in Java


The most productive way of developing a servlet/JSP app is to structure your app to comply with the Servlet specification. This means creating a WEB-INF directory under your app directory, adding all JAR's to WEB-INF/lib and instructing Eclipse/NetBeans to compile Java sources to WEB-INF/classes. This way, as long as Tomcat's Context reloadable setting is set to true, your app will be reloaded automatically whenever a Java class is updated. No need to rebuild the project and restart Tomcat.

Unfortunately, you are not always free to structure your app. For instance, if your team is using Maven, chances are you will be working with a Maven directory structure. You'll probably have a structure like this:

web-app/
         src/
             main/
                  java/
                  resources/
                  webapp/
                         WEB-INF/
                                 classes/
         target/
                classes/

Not too worry. You can still be productive if you are using Tomcat 7. Simply use its VirtualDirContext implementation of Resource in your Tomcat Context declaration.

Here is an example (you need to declare this in your server.xml file in $TOMCAT_HOME/conf or a Context file)

<Context path="/myapp" docBase="/home/temp/shopping/web" reloadable="true">
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <Resources className="org.apache.naming.resources.VirtualDirContext"
        extraResourcePaths="/WEB-INF/classes=/path1/classes,/WEBINF/classes=/path2,/css=/path3"/>
    <Loader className="org.apache.catalina.loader.VirtualWebappLoader"
        virtualClasspath="/home/temp/target/lib/homegrown.jar" />
    <JarScanner scanAllDirectories="true" />
</Context>

You can find more info here.

This will not work with Tomcat 8, though, because Tomcat 8 removed VirtualDirContext. You can, however, use symlinks in Tomcat 8 to enjoy the same benefit.

More on servlet/JSP programming can be found in my book "Servlet & JSP: A Tutorial, 2nd Edition" (ISBN 9781771970273)


Tracking Session Expiration in the Browser with WebSocket

by budi kurniawan


Posted on Sunday Dec 13, 2015 at 11:26PM in Java


The codes in this blog are borrowed from my book "Servlet & JSP: A Tutorial, 2nd Edition" (ISBN 9781771970273)

There are many reasons why you would want the browser to know when the HttpSession has expired. First, there are many pages and resources that can only be accessed by authenticated users. When a user’s HttpSession expires, also gone is the user’s proof he’s been authenticated, which is commonly stored in the HttpSession. Controlling access to these resources after the HttpSession expired proves difficult, especially in the era of AJAX programming where resources are often accessed without the user explicitly initiating it.

The second reason why you would want the browser to be notified when the HttpSession expires is to protect resources that are to be consumed by authorized eyes only. If the browser can be notified when such an important event occurs, it can be instructed to forward to a new page or delete the content of its HTML body.

This problem is hard to crack since you cannot send an HTTP request to the server to check if the HttpSession has expired, because doing so will prolong the life of the HttpSession. One common solution is to create a timer on the browser side that gets reset every time the browser makes an attempt to connect the server. This solution works but can be difficult to write.

The following example (in project websocket-config) shows how WebSocket can be used to solve this very old problem in web programming. This example works by persuading the browser to open a WebSocket connection to the server. The connect request is intercepted and the WebSocket Session is added as an attribute to the HttpSession. When the HttpSession expires, the WebSocket Session is retrieved and used to send a message to the browser. To get notified when the HttpSession is about to be destroyed, you need to write an HttpSessionListener and implement its sessionDestroyed method. This method is called right before the HttpSession is invalidated.

The main component of this application is the HttpSessionConfigurator class in Listing 21.8. The modifyHandshake method of this class retrieves the HttpSession object and puts it in the user properties map.

Listing 21.8: The HttpSessionConfigurator class

package configurator;
import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;

public class HttpSessionConfigurator extends 
        ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig config,
            HandshakeRequest request,
            HandshakeResponse response) {
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        if (httpSession != null) {
            config.getUserProperties().put("HTTP_SESSION", httpSession);
        }
    }
}

The endpoint in Listing 21.9 is used to link the WebSocket Session with the HttpSession. Note that the @ServerEndpoint annotation has a configurator attribute that is assigned the configurator class in Listing 21.8.

Listing 21.9: The HttpSessionConfigurationEndpoint class

package endpoint;
import configurator.HttpSessionConfigurator;
import javax.servlet.http.HttpSession;
import javax.websocket.EndpointConfig;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value="/config", 
        configurator = HttpSessionConfigurator.class)
public class HttpSessionConfiguratorEndpoint {
    
    @OnOpen
    public void open(Session session, EndpointConfig config) {
        HttpSession httpSession = (HttpSession) 
                config.getUserProperties().get("HTTP_SESSION");
        if (httpSession != null) {
            httpSession.setAttribute("WEBSOCKET_SESSION", session);
        }
    }
    
}

Next is the ExpiryTrackerHttpSessionListener class in Listing 21.10. Its contextDestroyed method gets called before an HttpSession is about to be invalidated. The method also receives the HttpSession. The method retrieves the WebSocket Session and uses it to send a message to the browser.

Listing 21.10: The ExpiryTrackerHttpSessionListener class

package listener;
import java.io.IOException;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import javax.websocket.Session;

@WebListener
public class ExpiryTrackerHttpSessionListener 
        implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent event) {
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        HttpSession httpSession = event.getSession();
        Session websocketSession = (Session)
                httpSession.getAttribute("WEBSOCKET_SESSION");
        if (websocketSession != null) {
            try {
                websocketSession.getBasicRemote().sendText("expired");
            } catch (IOException ex) {
            }
        }
    }
}

Finally, the JSP page in Listing 21.11 is an example page that opens a WebSocket connection. If the HttpSession expires when the browser is showing this page, the server sends a message via the WebSocket and the browser gets redirected to a login page.

Listing 21.11: The index.jsp page

<!DOCTYPE HTML>
<!--${cp=pageContext.request.contextPath}-->
${session.setMaxInactiveInterval(60)}
<html>
   <head>
       <title>Important page</title>
   </head>
   <body>
        <p>This page contains confidential information that must be erased when
           the user session on the server expires</p>
        <script type="text/javascript">
            if ("WebSocket" in window) {
                var uri = "ws://" + document.location.host 
                        + "${cp=="/"? "" : cp}" + "/config";
                var ws = new WebSocket(uri);
                ws.onmessage = function (event) {
                    if (event.data == "expired") {
                        window.location.href = "expired.html";
                    }
                };
            }
        </script<
   </body>
</html>


Is String concatenation still a taboo?

by budi kurniawan


Posted on Monday Sep 01, 2014 at 10:23PM in Java


Every good Java programmer knows that String objects are immutable and a String concatenation always creates a new String and is therefore an expensive operation that should be avoided. In other words, code like this is a taboo:

String s = "Hello";
s += ", World";
Or, is it?

For years, we've been advised to use StringBuilder instead, but today's Java compilers are more intelligent than ever. The Oracle Java compiler (and probably others) will convert the code above to something like this:

StringBuilder builder = new StringBuilder("Hello");
builder.append(", World");
String s = builder.toString();

How do you prove this? If you have Eclipse installed on your computer, simply create a test class and double-click the .class file in the Navigator view. The disassembled bytecode would look like this:

     0  ldc  [16]
     2  astore_1 [s1]
     3  new java.lang.StringBuilder [18]
     6  dup
     7  aload_1 [s1]
     8  invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [20]
    11  invokespecial java.lang.StringBuilder(java.lang.String) [26]
    14  ldc  [29]
    16  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [31]
    19  invokevirtual java.lang.StringBuilder.toString() : java.lang.String [35]
    22  astore_1 [s1]

See how in Line 3 the bytecode creates a StringBuilder?

So, should you start concatenating Strings because it's shorter than using StringBuilder? It depends. If every member in your team knows that compilers are smart, then yes. If not, your manager might think you don't even know the basic rule of working with Strings. Who says this will not cause a delay of your promotion?