Wednesday, July 27, 2011

Mock Table utility for CRUD operations

While learning a new technology we may need a database table to store the data.
But creating a database, setting up jdbc connection and writing crud operation may be cumbersome.

So I thought it would be good to have some mock utility to represent a table which can be used just like a database table.

Here is what I came up with.

package com.sivalabs.sample.util;
import java.io.Serializable;

public interface Identifiable<K> extends Serializable
{
 public void setId(K id);
 public K getId(); 
}


package com.sivalabs.sample.util;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public abstract class Table<PK extends Object, T extends Identifiable<PK>>
{
 protected final Map<PK, T> table = new HashMap<PK, T>();
 public abstract PK getNextId();
 
 protected Table()
 {
 }
 
 public void create(T obj)
 {
  if(table.containsKey(obj.getId()))
  {
   throw new RuntimeException("PrimaryKey ["+obj.getId()+"] already exists");
  }
  obj.setId(getNextId());
  table.put(obj.getId(), obj);
 }
 
 public Collection<T> getAll()
 {
  return table.values();
 }
 
 public T getById(PK id)
 {
  return table.get(id);
 }
 
 public void update(T obj)
 {
  if(!table.containsKey(obj.getId()))
  {
   throw new RuntimeException("PrimaryKey ["+obj.getId()+"] doesn't exists");
  }
  table.put(obj.getId(), obj);
 }
 
 public void delete(T obj)
 {
  delete(obj.getId());
 }
 
 public void delete(PK id)
 {
  if(!table.containsKey(id))
  {
   throw new RuntimeException("PrimaryKey ["+id+"] doesn't exists");
  }
  table.remove(id);
 }
}

Let us create a pojo Message.java.

package com.sivalabs.sample;

import java.util.Date;
import com.sivalabs.sample.util.Identifiable;

public class Message implements Identifiable<Integer>
{
 private static final long serialVersionUID = 1L;
 
 private Integer id;
 private String text;
 private String postedBy;
 private Date postedDate = new Date();
 public Message()
 {
 }
 
 public Message(Integer id, String text, String postedBy, Date postedDate)
 {
  this.id = id;
  this.text = text;
  this.postedBy = postedBy;
  this.postedDate = postedDate;
 }

 public Integer getId()
 {
  return id;
 }
 public void setId(Integer id)
 {
  this.id = id;
 } 
 //setters, getters for text, postedBy, postedDate 
}

Now let us create a mock table for storing Messages.
The Message table needs to extend Table and provide what is the type of primary key and what type of objects MessageTable is going to contain using generics <Integer, Message>.

package com.sivalabs.sample.util;
import java.util.concurrent.atomic.AtomicInteger;
import com.sivalabs.sample.Message;

public class MessageTable extends Table<Integer, Message>
{
 private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0);
 @Override
 public Integer getNextId()
 {
  return ATOMIC_INTEGER.incrementAndGet();
 } 
}

Now let us create a MessageService which holds an instance of MessageTable and expose the CRUD operations to clients.

package com.sivalabs.sample;

import java.util.Collection;
import java.util.Date;
import com.sivalabs.sample.util.MessageTable;


public class MessageService
{
 private static final MessageTable MESSAGE_TABLE = new MessageTable();
 static
 {
  MESSAGE_TABLE.create(new Message(1, "Message1 Text", "Siva", new Date()));
  MESSAGE_TABLE.create(new Message(2, "Message2 Text", "Prasad", new Date()));
  MESSAGE_TABLE.create(new Message(3, "Message3 Text", "Prasad", new Date()));
  MESSAGE_TABLE.create(new Message(4, "Message4 Text", "Siva", new Date()));  
 }
 
 public Collection<Message> getMessages()
 {
  return MESSAGE_TABLE.getAll();
 }

 public Message getMessage(Integer id)
 {
  return MESSAGE_TABLE.getById(id);
 }

 public void saveMessage(Message message)
 {
  MESSAGE_TABLE.create(message);
 }

 public void updateMessage(Message message)
 {
  MESSAGE_TABLE.update(message);
 }

 public void deleteMessage(Integer id)
 {
  MESSAGE_TABLE.delete(id);
 }
}


Now if you want to create a mock table for another pojo User.java it is simple.

package com.sivalabs.sample.util;
import java.util.concurrent.atomic.AtomicInteger;
import com.sivalabs.sample.User;

public class UserTable extends Table<Integer, User>
{
 private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(0);
 @Override
 public Integer getNextId()
 {
  return ATOMIC_INTEGER.incrementAndGet();
 } 
}

If the primary key is always an auto incremented integer value we can move getNextId() method to Table.java. Then creating mock table becomes even more simpler.

package com.sivalabs.sample.util;
import com.sivalabs.sample.User;

public class UserTable extends Table<Integer, User>
{
  
}

1 comment: