web

How to Add Expiry Date on Your Static Files using Java’s Servlet Filter

Perhaps there would be some people wondering, why should i use expiry date on my static files? Well for a first-time visitor to your page may have to make several HTTP requests to load all your web page’s content, but by using the Expires header you make those components cacheable. This avoids unnecessary HTTP requests on subsequent page views. Expires headers are most often used with images, but they should be used on all components including scripts, stylesheets, and Flash components.

But dont forget, using a far future Expires header affects page views only after a user has already visited your site. It has no effect on the number of HTTP requests when a user visits your site for the first time and the browser’s cache is empty. Therefore the impact of this performance improvement depends on how often users hit your pages with a primed cache.

Okay, so basically i use a simple ServletFilter to add Expiry header on each static contents, on this example would be .css, .png and .gif files. So here is my code,

package com.edw.fw.server.filter;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

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;

public class ExpiryFilter implements Filter {

	// add a five years expiry
	private Integer years = 5;

	@Override
	public void destroy() {
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		if (years > -1) {
			Calendar c = Calendar.getInstance();
			c.setTime(new Date());
			c.add(Calendar.YEAR, years);

			// HTTP header date format: Thu, 01 Dec 1994 16:00:00 GMT
			String o = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss zzz")
					.format(c.getTime());
			((HttpServletResponse) response).setHeader("Expires", o);
		}

		chain.doFilter(request, response);
	}

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

And dont forget to register your Filter to your web.xml file

		<!--  
			expiration date filter
		-->
	  	<filter>
			<description>Set cache expiry for static content</description>
			<filter-name>ExpiryFilter</filter-name>
			<filter-class>com.edw.fw.server.filter.ExpiryFilter</filter-class>
		</filter>
		<filter-mapping>
			<filter-name>ExpiryFilter</filter-name>
			<url-pattern>*.css</url-pattern>
			<dispatcher>REQUEST</dispatcher>
		</filter-mapping>
		<filter-mapping>
			<filter-name>ExpiryFilter</filter-name>
			<url-pattern>*.png</url-pattern>
			<dispatcher>REQUEST</dispatcher>
		</filter-mapping>
		<filter-mapping>
			<filter-name>ExpiryFilter</filter-name>
			<url-pattern>*.gif</url-pattern>
			<dispatcher>REQUEST</dispatcher>
		</filter-mapping>

This is what it looks like on my browser’s http log,

as you can see, my http request get 304 not modified header, due to accessing my browser’s cache instead of the targetted web page.

Okay, i hope this helped other. Have Fun 🙂

A java.lang.IllegalArgumentException when Using SpringMVC @PathVariable

Another exception happened to me today while im deploying my application to Tomcat 7, somehow the error (again) never happen on my IDE. The error is related to Spring MVC’s @PathVariable. Below is the complete stacktrace for the error.

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.
	org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:894)
	org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:778)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
	com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
	org.springframework.security.web.FilterChainProxy$VirtualFilterChain .doFilter(FilterChainProxy.java:330)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor .invoke(FilterSecurityInterceptor.java:118)
	org.springframework.security.web.access.intercept.FilterSecurityInterceptor .doFilter(FilterSecurityInterceptor.java:84)

And this is the suspected method which raise exception,

    @RequestMapping(value ="/baculsoft/news/view/{id}", method = RequestMethod.GET)
    public String newsView(ModelMap modelMap, 
                        @PathVariable String id) {
        modelMap.put("news", newsService.get(id);
        return "news/view";
    }

The workaround is actually simple, below is how to deal with it,

    @RequestMapping(value ="/baculsoft/news/view/{id}", method = RequestMethod.GET)
    public String newsView(ModelMap modelMap, 
                        @PathVariable("id") String id) {
        modelMap.put("news", newsService.get(id);
        return "news/view";
    }

Actually very simple workaround, but since i have hundreds of methods using @PathVariable, it’s not so simple anymore. And the weird thing is, the .war exported from Eclipse IDE run perfectly, only .war created from Netbeans that raise exception. I dont know why, but somehow Netbeans’ ant create a different war compared to Eclipse’s war file.

After sometimes googling, i found out that it happens due to javac’s debug parameter on Netbeans’ ant, changing “debug” default value into “on” on Netbeans’ build-impl.xml makes my war file run perfectly on Tomcat 7. Well i hope it hepled others, cheers (B)

Simulate A Post Request Using Java

Today, i’ll do a simple example on how to simulate a http post request using Apache Common Http Components. This is a usefull utility, because i use it heavily on many projects, specially to do a simple messaging between desktop clients and the server side. Very simple, very lightweight and also very reliable.

Okay, first i start with the server version of the application. I create a new WebProject on Netbeans, create a simple servlet and deploy it on tomcat. This is a very simple servlet to print on netbeans console and give response whether 0 if failed, or 1 if succeed.

package com.edw.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;

public class LoginServlet extends HttpServlet {
    
    private Logger logger = Logger.getLogger(LoginServlet.class);
    
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            
            logger.debug("receiving post " + username + " and " + password);
            response.getWriter().write("1");
        } catch (Exception e) {
            logger.error(e,e);
            response.getWriter().write("0");
        }                
    }
}

As usual, i register my servlet on web.xml.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.edw.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <url-pattern>/loginServlet</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

And now is my client’s side Java application.

package com.edw.postsimulator;

import java.util.ArrayList;
import java.util.List;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class PostSimulator {
    
    // this is your target url
    private static String url = "http://localhost:8084/WebTestPost/loginServlet";
    
    public static void main(String[] args) throws Exception  {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httpPost = new HttpPost(url);

        // set the parameters
        List <NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("username", "edwin"));
        nvps.add(new BasicNameValuePair("password", "dodol"));

        // set the encoding
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, Consts.UTF_8));

        // send the http request and get the http response
        HttpResponse response = httpclient.execute(httpPost);
        HttpEntity resEntity = response.getEntity();
		
        // read the server's response contents
        System.out.println(EntityUtils.toString(resEntity));
    }
}

These are what is written on my Netbean’s console,

And this is my Netbean’s project configurations

Hope it helped others, Cheers :-[

Weird Error when Connecting Spring’s JavaMailSender to Postfix

I had a weird error today when trying to connect to my server’s postfix mail server. It’s weird because i never had this kind of error when connecting to Google Mail server. This is the error that i see on postfix’s log.

Mar 26 01:50:19 localhost postfix/smtpd[24907]: connect from localhost[127.0.0.1]
Mar 26 01:50:19 localhost postfix/smtpd[24907]: setting up TLS connection from localhost[127.0.0.1]
Mar 26 01:50:19 localhost postfix/smtpd[24907]: SSL_accept error from localhost[127.0.0.1]: 0
Mar 26 01:50:19 localhost postfix/smtpd[24907]: warning: TLS library problem: 24907:error:14094416:SSL routines:SSL3_READ_BYTES:sslv3 alert certificate unknown:s3_pkt.c:1193:SSL alert number 46:
Mar 26 01:50:19 localhost postfix/smtpd[24907]: lost connection after STARTTLS from localhost[127.0.0.1]
Mar 26 01:50:19 localhost postfix/smtpd[24907]: disconnect from localhost[127.0.0.1]

This is my email configuration on Spring’s applicationContext.xml.

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
	<property name="host" value="localhost"/>
	<property name="port" value="25"/>
	<property name="username" value="admin@whatever.com"></property>
	<property name="password" value="password"></property>
	<property name="javaMailProperties">
		<props>
			<prop key="mail.smtp.auth">true</prop>
			<prop key="mail.smtp.starttls.enable">true</prop>
		</props>
	</property>
</bean>

After googling for a while, i found out that somehow the error happen because of TLS problem. The workaround is actually easy, i disabled the starttls property on bean mailSender.

<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
	<property name="host" value="localhost"/>
	<property name="port" value="25"/>
	<property name="username" value="admin@whatever.com"></property>
	<property name="password" value="password"></property>
	<property name="javaMailProperties">
		<props>
			<prop key="mail.smtp.auth">true</prop>
			<prop key="mail.smtp.starttls.enable">false</prop>
		</props>
	</property>
</bean>

Bagaimana Membuat Autostart Aplikasi Java

Barusan kawan gw, Benni Purwonegoro SKom, sharing tentang masalah yang dia temukan serta bagaimana cara workaround-nya. Inti masalahnya sebenarnya sederhana, kebetulan beliau punya server (Windows Server) yang diinstall aplikasi java (web-based). Namun karena servernya sering restart, aplikasi java-nya juga jadi sering down. Oleh sebab itu dicari cara supaya aplikasi java yang diinstall menjadi aplikasi startup yang autorun otomatis setiap server dinyalakan.

Awalnya gw mengajukan supaya dibuat shortcut dari .bat yang kemudian ditaro dibawah folder startup, workaround lainnya adalah dengan Apache Procrun. Namun workaround dari beliau ternyata lebih simple dan efektif, hanya melakukan sedikit modifikasi regedit.

Berikut adalah petunjuk daari beliau

  1. Buat .bat file yang akan mengeksekusi aplikasi java.
  2. Buat new string value di key HKEY_LOCAL_MACHINE\ SOFTWARE\ Microsoft\ Windows\ CurrentVersion\Run
  3. Kemudian masukkan path file .bat yang baru dicreate sebagai value
  4. Langsung tes dan berdoa

Wow gan, workaround ente manjur sekali (H)