Sunday, May 17, 2009

Install Linux (Ubuntu) from USB drive

Recently one of our old laptop was crashed, so I had to re-install the operating system. We lost the Windows XP CD came with it, so installed XP from another CD. New installation was not ready to accept the keys mentioned on the sticker at the bottom of the laptop. So I decided to install Ubuntu 9.04 using a USB drive. This document has detailed information about USB installation. As no Ubuntu installation was available at that time, so creating a boot USB drive from downloaded ISO file was the only option and UNetbootin did the task nicely on Dell Latitude D630. But IBM ThinkPad R51 refused to boot from the USB disk (Kingston DataTraveler 4GB), anyway I was prepared for such failures and tried with another USB drive (Sandisk Cruzer micro 2GB), which worked well. On first boot system recognized my wireless network and connected instantly along with nice sound blowing from speakers.

My experience with USB installation was pretty nice and it took just 15 minutes for the whole exercise. Ubuntu installation was much easier then Windows XP.

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.