Thursday, May 26, 2011

Dynamic Behavior Addition

Suppose you are building a system that sorts a set of numbers. User has option to choose various algorithms. You allow 3rd party sorting algorithms to be added to system on the fly without needing application restart. All this facilities using a UI. Is it possible to do it? What would be the best way to do it?

My Answer (I have not tried it, but believe it should work.)
1. Create an interface SortAlgorithm containing sort (List) method.
2. Publish its source and .class file.
3. Design a table SortAlgorithms with two columns algo_name and class_name.
4. Provide a UI for 3rd party vendors to upload their concrete implementation for SortAlgorithm.
5. Put the .class file of 4 in class-path and create an entry in the table.
6. Your UI would start listing the new algorithm picked up from the same table.
7. If user chooses new algorithm, load its corresponding class with its name in that table.
8. Your code was always using SortAlgorithm interface so it never needed changes.

Does this approach makes sense to add new behaviors in the system?

Tuesday, March 22, 2011

Printing number series with multiple threads

Problem: Write a code to print numbers 1 to 10 with using two threads such that one thread prints 1, 3, 5, 7, 9 and other thread prints 2, 4, 6, 8, 10


Solution:
Below is the code I wrote first but do not believe it to be an elegant solution, I plan to write a more elegant solution later but let's see when it happens.
With this solution, I ran into an issue when I used Integer class instead of MyInteger, could you spot the issue?

 public class AlternatePrint implements Runnable {  
int id;
MyInteger number;
// Integer number;
AlternatePrint(int id, MyInteger number) {
this.id = id;
this.number = number;
}
public void run() {
int last = id;
while (number.getValue() <= 10) {
synchronized (number) {
if (last != number.getValue()) {
System.out.println("Thread: " + id + " printing: "
+ number.getValue());
number.setValue(number.getValue() + 1);
last = number.getValue();
// number++;
// last = number;
}
try {
number.wait(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
System.out.println("Thread: " + id + " exiting!!!");
}
public static void main(String[] args) {
AlternatePrint a, b;
MyInteger o = new MyInteger(1);
a = new AlternatePrint(1, o);
b = new AlternatePrint(2, o);
new Thread(a).start();
new Thread(b).start();
System.out.println("Main Thread exiting!!!");
}
}
class MyInteger {
private int value;
MyInteger(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}

Tuesday, March 8, 2011

Find common elements in two sets of numbers.

Problem: Find common elements between 2 sets of numbers received from console.

For example: For following input:
Set A - > [ 1,4 ,7,9,11]
Set B - > [4, 9 , 13]
Output should be:
[4, 9]


Source Code:


 import java.io.BufferedReader;  
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
/**
*
* @author bhavin
*
*/
public class NumberUtil {
/**
* Delimiter used for separating numbers in string list consumed by createIntegerList
*/
public static final String SPACE_DELIMITER = " +";
/**
* Creates list of integers from the delimited list of numbers.
*
* @param elementsStr String containing numbers separated by delimiter
* @param delimiter Delimiter used to separate numbers in elementsStr
* @return List of valid-numbers present in elementsStr
*/
public static List<Integer> createIntgerList(String elementsStr, String delimiter) {
List<Integer> intList = new ArrayList<Integer>();
if (elementsStr == null)
return intList;
String[] strArray = elementsStr.split(delimiter);
for (int idx = 0; idx < strArray.length; idx++) {
try {
intList.add(Integer.parseInt(strArray[idx]));
} catch (NumberFormatException exception) {
//if string to number conversion fails, ignore the exception
System.out.println("'" + strArray[idx]
+ "' is possibly an invalid input, ignoring it.");
}
}
return intList;
}
/**
*
* @param firstList first list of numbers
* @param secondList second list of numbers
* @return return set of numbers which are common to both lists
*/
public static Set<Integer> getCommonElements(List<Integer> firstList,
List<Integer> secondList) {
List<Integer> smallList = null;
List<Integer> bigList = null;
Map<Integer, Integer> elements = new HashMap<Integer, Integer>();
Set<Integer> commonElements = new HashSet<Integer>();
if (firstList == null || secondList == null
|| firstList.size() == 0 || secondList.size() == 0)
return commonElements;
// For small list prepare the map
if (firstList.size() < secondList.size()) {
smallList = firstList;
bigList = secondList;
} else {
smallList = secondList;
bigList = firstList;
}
// prepare a map of elements present in the first map
for (Integer element : smallList) {
elements.put(element, element);
}
for (Integer element : bigList) {
if (elements.remove(element) != null) {
commonElements.add(element);
// when all, we have exhausted first list, no need to
// continue
if (elements.size() == 0)
break;
}
}
return commonElements;
}
public static void main(String[] args) {
List<Integer> firstElementList = null;
List<Integer> secondElementlist = null;
String firstElementListStr = null;
String secondElementListStr = null;
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(inputStreamReader);
try {
System.out.print("Enter first set: ");
firstElementListStr = br.readLine();
System.out.print("Enter second set: ");
secondElementListStr = br.readLine();
} catch (IOException e) {
System.out.println("Something went wrong while reading input,"
+ " exception stack-trace is printed below.");
e.printStackTrace();
} finally {
try {
br.close();
inputStreamReader.close();
} catch (IOException e) {
System.out.println("Something went wrong while closing "
+" stream-readers, exception stack-trace is printed below.");
e.printStackTrace();
}
}
firstElementList = createIntgerList(firstElementListStr,
SPACE_DELIMITER);
secondElementlist = createIntgerList(secondElementListStr,
SPACE_DELIMITER);
Set<Integer> commonElements = getCommonElements(firstElementList,
secondElementlist);
if (commonElements != null && commonElements.size() != 0)
System.out.println("Common Elements: " + commonElements);
else
System.out.println("There are no common elements.");
}
/**
* A unit-test method to test combined logic of createIntegerList and getCommonElements method.
*/
public static void testNumberUtil() {
String numberStr1 = "1 4 7 9 11";
String numberStr2 = "4 9 13";
String numberStr3 = "1 4 4";
String numberStr4 = "2";
String numberStr5 = "2 2 2x";
List<Integer> elements1;
List<Integer> elements2;
Set<Integer> commonElements;
//few common elements test-case
elements1 = createIntgerList(numberStr1, SPACE_DELIMITER);
elements2 = createIntgerList(numberStr2, SPACE_DELIMITER);
commonElements = getCommonElements(elements1, elements2);
if (commonElements.size() != 2)
System.out.println("Program fails for input: "
+ numberStr1 + " and " + numberStr2);
if (commonElements.contains(new Integer(4)) == false
|| commonElements.contains(new Integer(9)) == false )
System.out.println("Program fails for input: "
+ numberStr1 + " and " + numberStr2);
//no common elements test-case
elements1 = createIntgerList(numberStr3, SPACE_DELIMITER);
elements2 = createIntgerList(numberStr4, SPACE_DELIMITER);
commonElements = getCommonElements(elements1, elements2);
if (commonElements.size() != 0)
System.out.println("Program fails for input: "
+ numberStr3 + " and " + numberStr4);
//part-invalid input
elements1 = createIntgerList(numberStr4, SPACE_DELIMITER);
elements2 = createIntgerList(numberStr5, SPACE_DELIMITER);
commonElements = getCommonElements(elements1, elements2);
if (commonElements.size() != 1)
System.out.println("Program fails for input: "
+ numberStr4 + " and " + numberStr5);
if (commonElements.contains(new Integer(2)) == false)
System.out.println("Program fails for input: "
+ numberStr4 + " and " + numberStr5);
//null input
elements1 = createIntgerList(null, SPACE_DELIMITER);
elements2 = createIntgerList(null, SPACE_DELIMITER);
commonElements = getCommonElements(elements1, elements2);
if (commonElements.size() != 0)
System.out.println("Program fails for null inputs.");
}
}