Java, Maven, and Your Web Development Project
Maven is a project management tool designed to create a consistent build environment with minimal duplication of libraries or configuration. It is one of the top-level projects produced by the Apache Foundation and can be downloaded, free of charge, from the Apache Maven Web site.
In this second part of my series on Maven, an assumption is made that you are familiar with the basic functionality of Maven and that you can set up a project directory structure and project descriptor. In this article, I build a very simple Web application, along with JUnit tests for some of its functionality. The main function is to demonstrate the usefulness of Maven in the project development lifecycle—not necessarily the viability of the Web application itself.
Creating the Project
To begin, I need to set up a project directory structure. Although Maven can be fitted to a wide range of directory structures, I set up the directories in the order recommended by Apache. (This is merely for the sake of consistency, and is not required.) The directory structure is as follows:
example +--src +--main +--java +--com +--zarrastudios +--example +--webapp +--WEB-INF +--test +--java +--com +--zarrastudios +--example
If you read my previous article, you will notice that I added an additional directory named webapp under src/main. The JSPs, images, and other Web-specific files will be stored in this directory.
I created two Java source files inside the main Java directory structure. The first one is the example servlet that is accessed from the Web application. The code for that class is as follows:
package com.zarrastudios.example; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.ServletException; import java.io.IOException; public class ExampleServlet extends HttpServlet { public static final int ENCRYPT = 0; public static final int DECRYPT = 1; protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String key = req.getParameter("key"); String text = req.getParameter("text"); int direction = Integer.parseInt(req.getParameter("direction")); String result; Encrypter encrypter = new Encrypter(key); if (direction == ENCRYPT) { result = encrypter.encrypt(text); } else { result = encrypter.decrypt(text); } req.setAttribute("result", result); getServletContext().getRequestDispatcher("/receiver.jsp").forward(req, resp); } }
A quick review of the servlet shows that it is dependent on another class, Encrypter. The code for Encrypter.java is as follows:
package com.zarrastudios.example; import org.apache.log4j.Logger; import javax.crypto.Cipher; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import java.security.spec.KeySpec; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; public class Encrypter { private static final Logger log = Logger.getLogger(Encrypter.class); private KeySpec keySpec; private SecretKeyFactory keyFactory; private Cipher cipher; public Encrypter(String passkey) { if (passkey == null) { throw new IllegalArgumentException("Encryption key is null"); } try { keySpec = new DESKeySpec(passkey.getBytes("UTF8")); keyFactory = SecretKeyFactory.getInstance("DES"); cipher = Cipher.getInstance("DES"); } catch (Exception e) { log.error("Error initializing Encrypter", e); } } public String encrypt(String s) { try { cipher.init(Cipher.ENCRYPT_MODE, keyFactory.generateSecret(keySpec)); BASE64Encoder encoder = new BASE64Encoder(); return encoder.encode(cipher.doFinal(s.getBytes("UTF8"))); } catch (Exception e) { log.error("Error encrypting string", e); return null; } } public String decrypt(String s) { try { cipher.init(Cipher.DECRYPT_MODE, keyFactory.generateSecret(keySpec)); BASE64Decoder decoder = new BASE64Decoder(); byte[] decrypted = cipher.doFinal(decoder.decodeBuffer(s)); StringBuffer sb = new StringBuffer(); for (int i = 0; i < decrypted.length; i++) { sb.append((char)decrypted[i]); } return sb.toString(); } catch (Exception e) { log.error("Error decrypting string", e); return null; } } }
To make sure that this Encrypter class does what I want it to do, I want to test it. Utilizing JUnit, I wrote a straightforward test to confirm that it is encrypting and decrypting the code:
package com.zarrastudios.example; import junit.framework.TestCase; public class EncryptTest extends TestCase { private String passkey = "Mary had a little lamb"; private String message = "This is a test message 1234 56789 123 4567 " + "1234 56789 123 4567 1234 56789 123 4567 1234 56789 123 4567 " + "1234 56789 123 4567 1234 56789 123 4567 1234 56789 123 4567"; public void testEncryption() throws Exception { Encrypter e = new Encrypter(passkey); String encrypted = e.encrypt(message); assertTrue("Encrypted string is null", encrypted != null); String decrypted = e.decrypt(encrypted); assertTrue("Decrypted string is null", decrypted != null); assertTrue("Decrypted string does not match the original", decrypted.equals(message)); } }
The final pieces of "code" that need to be written for this example are the JSP pages. Because this is a very simple example, the index.jsp page merely has fields for the input without anything else.
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page import="com.zarrastudios.example.ExampleServlet"%><html> <head> <title> Example Encryption Servlet </title> </head> <body> <form action="example" method="POST"> <table> <tr> <td>Key</td> <td> <input type="text" name="key"/> </td> </tr> <tr> <td>Text</td> <td> <textarea name="text" rows="10" cols="40"></textarea> </td> </tr> <tr> <td colspan="2"> <input type="radio" name="direction" value="<%=ExampleServlet.ENCRYPT%>" checked>Encrypt <input type="radio" name="direction" value="<%=ExampleServlet.DECRYPT%>">Decrypt </td> </tr> <tr> <td align="center"> <INPUT TYPE="submit" VALUE="Do It!"> </td> </tr> </table> </form> </body> </html>
The receiver is even more simplistic. It simply displays the output in a text area:
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Encrypter response page</title> </head> <body> <textarea rows="10" cols="40"><%=request.getAttribute("result")%></textarea> </body> </html>
That completes the application. I would normally need to write a fairly complex ant build.xml file to put all this together, test it, and create a deployable war file.