It is common to find a random number between 2 given numbers… In our java application that we are working on, We had a need to find a random time between two given timestamp.. We felt it little challenging in the beginning… But later figured out a simple solution for the same… The steps for generating a random time between 2 timestamps really turned out to be very simple & this article is about how we achieved that…

If min and max are the 2 variables that are holding minimum and maximum values, & random is the random number that is to be generated, in java the random number is calculated in this way…

random = (Math.random() * (max - min) ) + min

Here Math.random() is a function in java that generates any random value between 0 & 1… We multiply that with the difference between max & min values and finally add the obtained result with the min value to get a random number between 2 given numbers.. This idea was set as the basement for our requirement too… Wondering how?? This is how it goes…

We use Calendar object which defaults to current date and time. We then set Hour, minute & second in the same object(If required we can set the year, month & date too).. Now we have the Calendar object with the date what we set or current date and time. Calendar class has a method named getTimeInMillis which will convert this timeStamp to a long value. This long value serves as the first min variable as in the example where we generate a random number between 2 different numbers.

Now in the same way we get the long value of the second timestamp too which is the max variable value. Using a similar calculation as above we get a random long number between 2 different long numbers which are the long time. Finally we construct the date object with the long value that we obtained.. This date object’s value is the random time stamp between 2 different Calendar objects and hence the we can generate random date/time between two different Calendar objects!!!! :-)

Here goes the code for that..

//code to generate random timestamp between morning 6 to evening 8 pm
public static void main(String args[]){
Calendar cdr = Calendar.getInstance();
cdr.set(Calendar.HOUR_OF_DAY, 6);
cdr.set(Calendar.MINUTE, 0);
cdr.set(Calendar.SECOND, 0);
long val1=cdr.getTimeInMillis();


cdr.set(Calendar.HOUR_OF_DAY, 20);
cdr.set(Calendar.MINUTE, 0);
cdr.set(Calendar.SECOND, 0);
long val2=cdr.getTimeInMillis();


Random r=new Random();
long randomTS=(long)(r.nextDouble()*(val2-val1))+val1;
Date d=new Date(randomTS);
System.out.println(d.toString());
}

PS: This will work even for generating random date between two different dates which can be a month/year gap.

Posted by Nivasini, filed under Java. Date: July 17, 2008, 7:04 pm | 1 Comment »

The topic of discussion in this would not be to explain what Hibernate is or its architecture or performance issues. The reader should have a minimum knowledge of how an ORM works and Java.

One of the main reasons to move to Hibernate is to improve performance of the entire application. Traditional JDBC application is expensive and a complex job for any developer (if no DBA is available) to write the SQL queries. The developer first has to get a connection to the Database, create a Statement/PreparedStatement, ResultSets and iterate the ResultSet and embed the values into the ValueObjects (VO). Once done, the developer must ensure to close all the resources that were open during this process.

How does Hibernate eliminate all these? Hibernate requires only a DataSource to be specified and all the work of opening a connection, creating statements and executing these queries are the dirty job done by Hibernate. This shall be point of discussion in the later posts.

Let’s take a complex SQL query and convert them to Hibernate and see its advantages.

SQL Query:

select modality_type,
count(case when scheduled_ts >= DATE(NOW()) and scheduled_ts < DATE(NOW() + INTERVAL 1 DAY )
and hospital_id= 'BS' then scheduled_ts else NULL END ) as scheduled,
count(case when completed_ts != '0000-00-00 00:00:00'
and scheduled_ts >= DATE(NOW()) and scheduled_ts < DATE(NOW() + INTERVAL 1 DAY )
and hospital_id= 'BS' then completed_ts else NULL END) as completed
from order_status where modality_type in ('CT','DX','NM','US','IR','MR','PX','VA')
group by modality_type

This query is a typical Cross-tab/Pivot query. The query results in showing three columns - Modality Type, Count of Exams Scheduled for today and Count of Exams completed for the day which is grouped by Modality Type.

Let’s see how this is done with Hibernate.

1. Create a value object/java bean
Lets call our VO as CompletedAgainstScheduled

Note: For easier understanding I’ll show only a few snippets


/**
* @hibernate.class table="order_status" lazy="false"
*/
public class CompletedAgainstScheduled implements Serializable {
private Long id;
private String hospitalId;
private String modalityType;
private String completedTimestamp;
private String scheduledTimestamp;
private int completed;
private int scheduled;
private int interpretedBy;


/**
* @return
*
* @hibernate.meta attribute="id" value="ID"
* @hibernate.id type="long" column="id" generator-class="native"
*/
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}

/** other setter and getters with hibernate mapping */

…..

/**
* get and set completed orders
*
* @return
*
* @hibernate.meta attribute="completedTimestamp" value="Completed Timestamp"
* @hibernate.property column="completed_ts" formula="case when completed_ts != '0000-00-00 00:00:00' then completed_ts else null end"
*/
public String getCompletedTimestamp() {
return completedTimestamp;
}
public void setCompletedTimestamp(String completedTimestamp) {
this.completedTimestamp = completedTimestamp;
}
}

For better understanding I’ve used XDoclet for Hibernate mapping.

When this class is compiled (using maven and xdoclet-plugin), it creates the Hibernate mapping file automatically.

So what is this class doing? @hibernate.class table="order_status" says that this VO is mapped to the table order_status in our database.

@hibernate.meta attribute="completedTimestamp" value="Completed Timestamp"
@hibernate.property column="completed_ts" formula="case when completed_ts != '0000-00-00 00:00:00' then completed_ts else null end"

The @hibernate.meta is basically for API Documentation and @hibernate.property column="completed_ts" is mapped to the attribute completedTimestamp in the Value Object.

Here is a very interesting concept: formula="case when completed_ts != '0000-00-00 00:00:00' then completed_ts else null end"
Why do this at all? Value Objects are ALWAYS mapped to a table and its attributes to columns. In the above Cross-tab query, we are deriving columns that are not in the table. Hence the formula on what should be done. We are counting number of rows for completed_ts that is not equal to “0000-00-00 00:00:00″. This formula will be embedded within the count() function.

NOTE: The case when.. is compatible only with MySQL and Oracle.

2. Hibernate Query
This section covers how the query is built in the DAO layer

Criteria criteria = getSession().createCriteria(CompletedAgainstScheduled.class)
.setProjection(
Projections.projectionList()
.add(Projections.groupProperty("modalityType").as("modalityType"))
.add(Projections.count("scheduledTimestamp").as("scheduled"))
.add(Projections.count("completedTimestamp").as("completed"))
)//.add(Restrictions.in("modalityType", modArr))
.add(Expression.ge("scheduledTimestamp", sdf.format(c.getTime())))
.add(Expression.lt("scheduledTimestamp", sdf.format(cd.getTime())))
.add(Expression.eq("hospitalId", hospitalId));


List csList = null;
if (criteria != null) {
csList = criteria.setResultTransformer(new AliasToBeanResultTransformer(CompletedAgainstScheduled.class)).list();
}

We have a ProjectionList that has modalityType (the column on which the resultSet should be grouped), scheduledTimestamp and completedTimestamp (the column that should be counted). Note that the attributes we are providing in the criteria. These are the attributes from the VO not the actual column names. This is what we call as HQL (Hibernate Query Language). When Hibernate complies this criteria, it generates a SQL dynamically and executes this at the database and returns a list of Objects which is of type CompletedAgainstScheduled.

Now, let’s do a little bit of post-mortem on how this Hibernate and SQL Query:

.add(Projections.groupProperty("modalityType").as("modalityType"))
.add(Projections.count("scheduledTimestamp").as("scheduled"))
.add(Projections.count("completedTimestamp").as("completed"))

is equivalent to

select modality_type,
count(scheduled_ts) as scheduled, count(completed_ts) as completed

We know that completedTimestamp is mapped to completed_ts in the table and returns an integer. But the column completed_ts itself is a datetime column. So, what happens to the integer? Well, the Projection says that count(completedTimestamp) which is mapped to completed_ts based on the formula we have specified in the VO and store the result in the completed attribute of the VO. Simple?

We can add as many expression as possible using the Expression class.

Once the query is executed, it returns a list of Objects which we have stored in csList. How does Hibernate know what and how to map? The ResultTransformer class does this job. It uses a sub-class called AliasToBeanResultTransformer class which is called for every row in the ResultSet and maps them to our VO.

That’s it. Very simple and intelligent.

If you have any doubts, do not hesitate to ask your questions.

In the next few series we’ll explore, Why Hibernate, XDoclets, Associations and other Hibernate related challenges.

Posted by Samanth, filed under Java. Date: July 11, 2008, 1:28 pm | 1 Comment »