Saturday, October 3, 2009

User Type Enumeration in Hibernate Annotations

There are times we would like to work with enum types in Hibernate, but we would like the enum name to be different then the enum value in the database. For example, we would like the Java enum name to be in upper case and the database enum name to be in lower case.

This feature can be achieved by creating a Hibernate user type enumeration. The code for this kind of enumeration can be found on the web, but I will post this code here anyway (that it will be easier). The main goal of this post, is to demonstrate how such a user type enumeration can be used with Annotations.

Here are the classes for creating the user type enumerations:

First is the interface defining a method: “getValue”, which returns the actual value of the enumeration. This value is the value that is written to the database table:

package com.bashan.blog.persistence;
/**
 * Utility class designed to allow dinamic fidding and manipulation of Enum
 * instances which hold a string value.
 */
public interface StringValuedEnum {
    /**
     * Current string value stored in the enum.
     * @return string value.
     */
    public String getValue();
}

The second class:

package com.bashan.blog.persistence;
/**
 * Utility class designed to inspect StringValuedEnums.
 */
public class StringValuedEnumReflect
{
  /**
   * Don't let anyone instantiate this class.
   *
   * @throws UnsupportedOperationException Always.
   */
  private StringValuedEnumReflect()
  {
    throw new UnsupportedOperationException("This class must not be instanciated.");
  }
  /**
   * All Enum constants (instances) declared in the specified class.
   *
   * @param enumClass Class to reflect
   * @return Array of all declared EnumConstants (instances).
   */
  private static <T extends Enum> T[]
  getValues(Class<T> enumClass)
  {
    return enumClass.getEnumConstants();
  }
  /**
   * All possible string values of the string valued enum.
   *
   * @param enumClass Class to reflect.
   * @return Available string values.
   */
  public static <T extends Enum & StringValuedEnum> String[]
  getStringValues(Class<T> enumClass)
  {
    T[] values = getValues(enumClass);
    String[] result = new String[values.length];
    for (int i = 0; i < values.length; i++)
    {
      result[i] = values[i].getValue();
    }
    return result;
  }
  /**
   * Name of the enum instance which hold the especified string value.
   * If value has duplicate enum instances than returns the first occurency.
   *
   * @param enumClass Class to inspect.
   * @param value     String.
   * @return name of the enum instance.
   */
  public static <T extends Enum & StringValuedEnum> String
  getNameFromValue(Class<T> enumClass, String value)
  {
    T[] values = getValues(enumClass);
    for (int i = 0; i < values.length; i++)
    {
      if (values[i].getValue().compareTo(value) == 0)
      {
        return values[i].name();
      }
    }
    return "";
  }
}

And the last one:

package com.bashan.blog.persistence;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Properties;
import java.lang.reflect.*;
import org.hibernate.HibernateException;
import org.hibernate.usertype.EnhancedUserType;
import org.hibernate.usertype.ParameterizedType;
import static com.todacell.ui.model.persistence.StringValuedEnumReflect.*;
//Please notice the calls to getNameFromValue *************************
public class StringValuedEnumType<T extends Enum & StringValuedEnum>
    implements EnhancedUserType, ParameterizedType
{
  /**
   * Enum class for this particular user type.
   */
  private Class<T> enumClass;
  /**
   * Value to use if null.
   */
  private String defaultValue;
  /**
   * Creates a new instance of ActiveStateEnumType
   */
  public StringValuedEnumType()
  {
  }
  public void setParameterValues(Properties parameters)
  {
    String enumClassName = parameters.getProperty("enum");
    try
    {
      enumClass = (Class<T>)Class.forName(enumClassName).asSubclass(Enum.class).
          asSubclass(StringValuedEnum.class); //Validates the class but does not eliminate the cast
    } catch (ClassNotFoundException cnfe)
    {
      throw new HibernateException("Enum class not found", cnfe);
    }
    setDefaultValue(parameters.getProperty("defaultValue"));
  }
  public String getDefaultValue()
  {
    return defaultValue;
  }
  public void setDefaultValue(String defaultValue)
  {
    this.defaultValue = defaultValue;
  }
  /**
   * The class returned by <tt>nullSafeGet()</tt>.
   *
   * @return Class
   */
  public Class returnedClass()
  {
    return enumClass;
  }
  public int[] sqlTypes()
  {
    return new int[]{Types.VARCHAR};
  }
  public boolean isMutable()
  {
    return false;
  }
  /**
   * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
   * should handle possibility of null values.
   *
   * @param rs    a JDBC result set
   * @param names the column names
   * @param owner the containing entity
   * @return Object
   * @throws HibernateException
   * @throws SQLException
   */
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        String value = rs.getString( names[0] );
        if (value==null) {
            value = getDefaultValue();
            if (value==null){ //no default value
                return null;
            }
        }
        String name = getNameFromValue(enumClass, value);
        Object res = name == null ? null : Enum.valueOf(enumClass, name);
        return res;
    }

  /**
   * Write an instance of the mapped class to a prepared statement. Implementors
   * should handle possibility of null values. A multi-column type should be written
   * to parameters starting from <tt>index</tt>.
   *
   * @param st    a JDBC prepared statement
   * @param value the object to write
   * @param index statement parameter index
   * @throws HibernateException
   * @throws SQLException
   */
  public void nullSafeSet(PreparedStatement st, Object value, int index)
      throws HibernateException, SQLException
  {
    if (value == null)
    {
      st.setNull(index, Types.VARCHAR);
    }
    else
    {
      st.setString(index, ((T)value).getValue());
    }
  }
  public Object assemble(Serializable cached, Object owner)
      throws HibernateException
  {
    return cached;
  }
  public Serializable disassemble(Object value) throws HibernateException
  {
    return (Enum)value;
  }
  public Object deepCopy(Object value) throws HibernateException
  {
    return value;
  }
  public boolean equals(Object x, Object y) throws HibernateException
  {
    return x == y;
  }
  public int hashCode(Object x) throws HibernateException
  {
    return x.hashCode();
  }
  public Object replace(Object original, Object target, Object owner)
      throws HibernateException
  {
    return original;
  }
  public String objectToSQLString(Object value)
  {
    return '\'' + ((T)value).getValue() + '\'';
  }
  public String toXMLString(Object value)
  {
    return ((T)value).getValue();
  }
  public Object fromXMLString(String xmlValue)
  {
    String name = getNameFromValue(enumClass, xmlValue);
    return Enum.valueOf(enumClass, name);
  }
}

Here is an example how this user type enumeration is used:

package com.bashan.blog.persistence;
public enum Gender implements StringValuedEnum {
  MALE("male"),
  FEMALE("female");
  private final String gender;
  Gender(final String gender)
  {
    this.gender = gender;
  }
  public String getValue()
  {
    return this.gender;
  }
}

And here is an example how the enum Gender is used as a member in an Hibernate Entity class Person:

package com.bashan.blog.persistence;
import org.hibernate.annotations.Entity;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.Type;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
@Entity
@Table(name = "person")
public class Person implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "person_id")
    private Integer personId;
    @Column(name = "first_name")
    @NotNull
    @Length(max = 50)
    private String firstName;
    @Column(name = "last_name")
    @NotNull
    @Length(max = 50)
    private String lastName;
    @Column(name = "birth_date")
    private Date birthDate;
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
    @JoinColumn(name = "person_id")
    @Column(name = "gender")
    @Type(type = "com.todacell.ui.model.persistence.StringValuedEnumType",
            parameters = @Parameter(name = "enum", value = "com.bashan.blog.persistence.Gender"))
    @NotNull
    private Gender gender;
    public Integer getPersonId() {
        return personId;
    }
    public void setPersonId(Integer personId) {
        this.personId = personId;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public Date getBirthDate() {
        return birthDate;
    }
    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }
    public Gender getGender() {
        return gender;
    }
    public void setGender(Gender gender) {
        this.gender = gender;
    }
}

The part in which the enum is used is marked in yellow.

You can grab all the sources for this post here.

Wednesday, September 30, 2009

Java Video to FLV (Flash Video) converter using FFmpeg

This post should have been written one or two years ago, with the Exit of YouTube and the big promise of the video content on the internet. But, as with every big buzz, the world has already taken it's next step towards smart phones and social networks.
YouTube and all the other video web sites allow uploading a video file. This video file can be shown on the web using a Flash based video player. The Flash video player can play FLV files. FLV file stands for: Flash Video File, which is a video file quite similar to WMV, MPG, AVI etc'.
So, as you can understand, the basic step towards building your own video site, is knowing to convert uploaded video files from all kinds to FLV. Doing the video conversion is a very complex job, requiring a great knowledge. Luckily for us, there is a great open source project named: FFmpeg, which, among the rest, allows us to convert almost any video from any type to any type. FFmpeg is a cross platform project. Whether you have Linux servers or Windows server (or any other popular operating system), FFmpeg will be available for you.
First, in order to do video conversion, we will have to download FFmpeg. If you are using Windows, you can find on the web compiled version ready for use. I found mine here.
FFmpeg is command line application. It has many options and parameters. In general, in order to convert a video file from any type to FLV we have to run FFmpeg with the following parameters:
ffmpeg -i "C:\filein.mp4" -ar 44100 -s 320x200 -qscale 5 "C:\fileout.flv"

This command takes a file named “filein.mp4” and converts it to FLV video file named: “fileout.flv”. The out video file dimensions is: 320x200. The parameter “qscale” defines the quality of the resulted video. Lower values give better quality. This parameter is not mandatory. Of course that the higher the quality of the video the higher the weight of the resulted file.

We will wrap the FFmpeg command line tool with Java code. We do it by simply executing the above command from Java. This will enable us to convert video to FLV file. These FLV files could be later played by some Flash Video Player (for example , to show the video on the web). A great free Flash based video player is: JW FLV Media Player. It supports many modern features required from a flash player. Some of them are:

  • Full events support allowing to control the video and get notifications from JavaScrip.
  • It allows using plugins.
  • It supports playing a video from any point (just like YouTube).
  • It can play videos directly from YouTube.

These are only some of the features this player has.

Let have a look at out Java Video to FLV converter. It’s code is very simple and straight forward:

package com.bashan.blog.video;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FLVConverter {
    private String ffmpegApp;
    public FLVConverter(String ffmpegApp) {
        this.ffmpegApp = ffmpegApp;
    }
    public void convert(String filenameIn, String filenameOut, int width, int height) throws IOException, InterruptedException {
        convert(filenameIn, filenameOut, width, height, -1);
    }
    public int convert(String filenameIn, String filenameOut, int width, int height, int quality)
            throws IOException, InterruptedException {
        ProcessBuilder processBuilder;
        if (quality > -1) {
            processBuilder = new ProcessBuilder(ffmpegApp, "-i", filenameIn, "-ar", "44100",
                    "-s", width + "*" + height, "-qscale", quality + "", filenameOut);
        } else {
            processBuilder = new ProcessBuilder(ffmpegApp, "-i", filenameIn, "-ar", "44100",
                    "-s", width + "*" + height, filenameOut);
        }
        Process process = processBuilder.start();
        InputStream stderr = process.getErrorStream();
        InputStreamReader isr = new InputStreamReader(stderr);
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null) ;
        {
        }
        return process.waitFor();
    }
}

And here is a small test program that does exactly what the above command line example is doing:

    public static void main(String[] args) throws Exception {
        FLVConverter FLVConverter = new FLVConverter("C:\\Users\\merdok\\IdeaProjects\\dev\\tools\\ffmpeg\\ffmpeg.exe");
        FLVConverter.convert("C:\\filein.mp4", "C:\\fileout.flv", 320, 200, 5);
    }
You can also download the converter here.

Monday, September 21, 2009

Generating random passwords with Java

There are times we we need to generate random passwords. For example, we want to send a user a new temporary password instead of an old one, or we just want to generate a strong password for the user, since users usually tend to choose weak password.
We will construct a random password generator written in Java. We will make it a bit smarter than simply producing a sequence of characters and numbers on a given size. The password generator, will be able to produce sequence of different sets of characters from different sizes and combine them together to a random password. For example, suppose we would like to generate 6 characters password combined from the following characters:
  • 2 small letters.
  • 2 capital letters.
  • 2 numbers

An example for such password is: gH1I9s.

our password generator is constructed from 2 classes

  • Main class: PasswordGenerator which responsible for generator random passwords according to desired logic.
  • Static inner class: PasswordLogic, which defines a set of characters and number of characters to choose from.

The PasswordLogic class is used as an input for the PasswordGenerator class, giving a description of the nature of the password we want to construct. The nature of the password is a set of characters from which we would like to construct the password and the number of characters we would like to use for constructing the password. The PasswordGenerator accepts array of PasswordLogic instances, and use these instances to construct a sequence of characters. We can sum the actions of the PasswordGenerator in these 2 simple steps:

  • First we scan each PasswordLogic instance, and produce from its characters array, a random characters set on the desired size.
  • Then we order all the characters we produced on a random sequence and combine them to a single string.

Of course, this is a very simple password generator. I find it good enough for most cases. A more complex and sophisticated password generator can be built on this basic one.

Let’s look at the password generator code:

package com.bashan.blog.password;
import java.util.*;
public class PasswordGenerator {
  private Random random = new Random();
  public static final char[] SMALL_LETTERS = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
      'o', 'p', 'q', 'r', 's', 'u', 'v', 'w', 'x', 'y', 'z'};
  public static final char[] CAPITAL_LETTERS = {
      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
      'W', 'X', 'Y', 'Z'};
  public static final char[] NUMBERS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
  private Set<Character> generateChars(char[] charArray, int size) {
    Set<Character> chars = new HashSet<Character>();
    int arrSize = charArray.length;
    for (int i = 0; i < size;) {
      char ch = charArray[random.nextInt(arrSize)];
      if (!chars.contains(ch)) {
        i++;
        chars.add(ch);
      }
    }
    return chars;
  }
  public String generate(PasswordLogic[] passwordLogics) {
    // Generate random characters
    List<Character> chars = new ArrayList<Character>();
    for (PasswordLogic passwordLogic : passwordLogics) {
      chars.addAll(generateChars(passwordLogic.chars, passwordLogic.numChars));
    }
    // Generate random sequence
    StringBuffer sb = new StringBuffer();
    int size = chars.size();
    Set<Integer> sequence = new HashSet<Integer>();
    for (int i = 0; i < size;) {
      int pos = random.nextInt(size);
      if (!sequence.contains(pos)) {
        i++;
        sb.append(chars.get(pos));
        sequence.add(pos);
      }
    }
    return sb.toString();
  }
  public static class PasswordLogic {
    private char[] chars;
    private int numChars;
    public PasswordLogic(char[] chars, int numChars) {
      this.numChars = numChars;
      this.chars = chars;
    }
    public char[] getChars() {
      return chars;
    }
    public void setChars(char[] chars) {
      this.chars = chars;
    }
    public int getNumChars() {
      return numChars;
    }
    public void setNumChars(int numChars) {
      this.numChars = numChars;
    }
  }
}

As you can see, the PasswordGenerator class defines 3 main sets of characters that can be used out-of-the box:

  • Upper case characters.
  • Small case characters.
  • Number characters.

Of course, you can defined your own sets of characters from which you would like to construct passwords.

Here is a small test program showing how the PasswordGenerator can be used in order to construct 2 passwords:

  • First password combined from 2 upper case characters, 2 small case characters and 2 numbers:

  • Second password combined from 3 numbers, 3 small case letters and 3 characters from the following: ~,!,@,#,$,%,^,&,*,(,),_,+
  public static void main(String[] args) {
    PasswordGenerator passwordGenerator = new PasswordGenerator();
    System.out.println(passwordGenerator.generate(new PasswordLogic[]{
        new PasswordLogic(CAPITAL_LETTERS, 2), new PasswordLogic(SMALL_LETTERS, 2),
        new PasswordLogic(NUMBERS, 2)}));
    System.out.println(passwordGenerator.generate(new PasswordLogic[]{
        new PasswordLogic(NUMBERS, 3), new PasswordLogic(SMALL_LETTERS, 3),
        new PasswordLogic(new char[] { '~','!','@','#','$','%','^','&','*','(',')','_','+' }, 3)}));
  }

And sample output for this test program:

6x5YmK
e^+819#an
Note, that if you don't like looking at so much characters in your eyes, you can simply rewrite this code to work with Strings instead.