Wednesday, April 22, 2009

Encoding warning with Maven 2.1.0

Recently I updated Maven to newest release (2.1.0) for a new project. Upgrade from 2.0.9 was smooth and all existing build scripts were working fine. While glancing at the logs emitted by Maven found this warning message-

[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!

This warning message was not emitted by Maven 2.0.9. Reason of this warning message is that maven (plugins) use platform default encoding and it notifies the users about the build being platform dependent. This article (http://docs.codehaus.org/display/MAVENUSER/POM+Element+for+Source+File+Encoding) has detailed information about this change. Instead of using platform default encoding, Maven can be instructed to use any encoding by adding following property in the pom.xml

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>


and it no longer emits the warning message.

Thursday, April 16, 2009

Contact Me application with Google Apps

Blogosphere is buzzing with Google App Engine for Java (GAEJ), so thought to give it a try. Google has put decent documentation to start with. Any Java web developer can start straight away with it. Only learning curve is to know the limitations of GAEJ. I would not talk about the features and limitations of it as there is lot of information is made available by Google and the people who dissected it before me :-)

I wanted to have a small application having contact form, which I wanted to put on my blog instead of displaying the email address. Here is the html / jsp page having contact form, gathering name, email, subject and the message-

<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core'%>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>Contact Me</title>
</head>

<body>
<h1>Contact Me!</h1>
<!-- Show error message, if any. -->
<font color='red'><c:out value="${requestScope.errorMessage}" escapeXml="false" /></font>

<form action="contactme" method="post">
<table>
    <tr>
        <td><label for="name">Name : </label></td>
        <td><input type="text" size="40" maxlength="40" title="Name" id="name" name="name" value="<c:out value='${param.name}' />" /></td>
    </tr>
    <tr>
        <td><label for="email">Email : </label></td>
        <td><input type="text" size="40" maxlength="60" title="Email" id="email" name="email" value="<c:out value='${param.email}' />" /></td>
    </tr>
    <tr>
        <td><label for="subject">Subject : </label></td>
        <td><input type="text" size="40" maxlength="80" title="Subject" id="subject" name="subject" value="<c:out value='${param.subject}' />" /></td>
    </tr>
    <tr>
        <td><label for="message" style="vertical-align: text-top">Message : </label></td>
        <td><textarea rows="10" cols="60" id="message" name="message" ><c:out value='${param.message}' /></textarea></td>
    </tr>
    <tr>
        <td colspan="2"><input type="submit" title="Submit" value="Submit">
        <br /> All fields are required.</td>
    </tr>
</table>
</form>
</body>
</html>

This is the same html / jsp, which we are using for several years. Okay, now here is the servlet backing this form-
package com.vinodsingh.gae.contact;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

import javax.mail.Address;
import javax.mail.Message;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.repackaged.org.apache.commons.logging.Log;
import com.google.appengine.repackaged.org.apache.commons.logging.LogFactory;

public class ContactMeServlet extends HttpServlet {

    private Log log = LogFactory.getLog(getClass());

    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        try {
            if (validate(req, resp)) {
                sendMail(req, resp);
                req.setAttribute("name", req.getParameter("name"));
                req.getRequestDispatcher("/thanks.jsp").forward(req, resp);
            } else {
                req.getRequestDispatcher("/index.jsp").forward(req, resp);
            }
        } catch (Exception e) {
            log.error("Error while processing contact request", e);
        }
    }

    // do very basic validation
    @SuppressWarnings("unchecked")
    private boolean validate(HttpServletRequest req, HttpServletResponse resp) {
        StringBuilder errorMessage = new StringBuilder();
        Map<String, String[]> params = req.getParameterMap();

        for (Entry<String, String[]> param : params.entrySet()) {
            String key = param.getKey();
            String value = param.getValue()[0];

            if ("name".equals(key))
                if (value.length() < 5)
                    errorMessage.append("Please enter a valid name.\n");

            if ("email".equals(key)) {
                if (value.length() < 12)
                    errorMessage.append("Please enter a valid email address.<br />");
                else if (value.indexOf('@') < 1)
                    errorMessage.append("Please enter a valid email address.<br />");
            }

            if ("subject".equals(key))
                if (value.length() < 15)
                    errorMessage.append("Please write a subject of at least 15 characters.<br />");

            if ("message".equals(key))
                if (value.length() < 50)
                    errorMessage.append("Please write a message of at least 50 characters.<br />");
        }

        if (errorMessage.length() > 0) {
            req.setAttribute("errorMessage", errorMessage.toString());
            return false;
        }

        return true;
    }

    // Send email
    private void sendMail(HttpServletRequest req, HttpServletResponse resp) {
        Session session = Session.getDefaultInstance(new Properties(), null);

        try {
            log.info("Got a contact request from: " + req.getParameter("email") + ", " + req.getParameter("name"));
            Message msg = new MimeMessage(session);
            msg.setFrom(new InternetAddress("me@mydomain.com", req.getParameter("name")));
            msg.setReplyTo(new Address[] { new InternetAddress(req.getParameter("email"), req.getParameter("name")) });

            // send email to both myself and the sender
            msg.addRecipient(Message.RecipientType.TO, new InternetAddress(req.getParameter("email"), req
                    .getParameter("name")));
            msg.addRecipient(Message.RecipientType.CC, new InternetAddress("me@mydomain.com", "Vinod Singh"));
            msg.setSubject(req.getParameter("subject"));
            msg.setText(req.getParameter("message"));
            Transport.send(msg);

        } catch (Exception e) {
            log.error("Error while sending emai", e);
        }
    }
}
Here only unusual thing is the mail sending part, where we do not need to have the SMTP thing to send the email, GAE will use application owner's email instead. All is well till now.

So it is the time to deploy the application. BOOM, deploy is failed miserably with this error-

Unable to upload:
java.lang.IllegalStateException: cannot find javac executable based on java.home, tried "C:\Program Files\Java\jre6\bin\javac.exe" and "C:\Program Files\Java\bin\javac.exe"
at com.google.appengine.tools.admin.AppAdminFactory$ApplicationProcessingOptions.getJavaCompiler(AppAdminFactory.java:325)
at com.google.appengine.tools.admin.Application.compileJavaFiles(Application.java:340)
at com.google.appengine.tools.admin.Application.compileJsps(Application.java:326)
at com.google.appengine.tools.admin.Application.createStagingDirectory(Application.java:235)
at com.google.appengine.tools.admin.AppAdminImpl.update(AppAdminImpl.java:39)
at com.google.appengine.tools.admin.AppCfg$UpdateAction.execute(AppCfg.java:469)
at com.google.appengine.tools.admin.AppCfg.<init>(AppCfg.java:114)
at com.google.appengine.tools.admin.AppCfg.main(AppCfg.java:59)


I have Java Development Kit 1.5.x and 1.6.x along with one more JRE on my machine (Vista), still GAE SDK can't find the 'javac' :-( This issue is logged here. Removing all JREs and keeping just the JDK makes it work. Okay finally my application is up and running and ready to receive the contact requests. I tried it myself and it worked as expected. As I was adding the contact person's email address in 'Reply-to' field, so I was expecting to GMail to fill that in 'TO' address on hitting the 'Reply' button. Here I came to know that GMail discards 'Reply-to' field altogether. Anyway this GMail issue has nothing to do with GAE.

GAE for Java looks a good step in adopting the Java for hobby. Before GAE if I wanted to create an application in java just for hobby, there was no hosting solution available at reasonable prices. While there are numerous options for PHP. I believe this will have a good impact on Java but if some of the restrictions removed as they do not conform to WORA concept of Java.

Saturday, April 11, 2009

Redirect HTTP to HTTPS on Apache

At times we need to run a website over HTTPS only and to retain the traffic coming to the website over HTTP, that needs to be redirected towards HTTPS. Though there are many ways to do so but this method looks easiest to me-

<VirtualHost *:80>
    ServerName mydomain.com

    RedirectPermanent / https://mydomain.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName mydomain.com

    # other SSL configuration goes here
</VirtualHost>


If only parts of the website (say /secure) needs to be HTTPS enabled then redirection can be done something like-

        RedirectPermanent /secure https://mydomain.com/secure