Sunday, February 13, 2011

Hibernate inverse="true" - Understanding The Logic Engine


What is “inverse”?

This is the most confusing keyword in Hibernate, at least i took quite a long time to understand what is it. The “inverse” keyword is always declared in one-to-many and many-to-many relationship (many-to-one doesn’t has inverse keyword), It defines which side is responsible to take care of the relationship.

Always put inverse=”true” in your collection variable?

There are many Hibernate articles try to explain the “inverse” with many Hibernate “official” jargon, which is very hard to understand (at least to me). In few articles, they even suggested that just forget about what is “inverse”, and always put the inverse=”true” in the collection variable. This statement is always true – “put inverse=true in collection variable”, but do not blindfold on it, try to understand the reason behind is essential to optimal your Hibernate performance.

“inverse”, can it change to “relationship owner”?

In Hibernate, only the relationship owner should maintain the relationship, and the “inverse” keyword is created to defines which side is the owner to maintain the relationship. However the “inverse” keyword itself is not verbose enough, I would suggest change the keyword to “relationship_owner“. The inverse=”true” means this is the relationship owner, whereas inverse=”false” (default) means it’s not.
Let’s go though a quick example to grab a draft idea of “inverse”…

Preparing the data for demonstration…

1. Database tables

This is a one-to-many relationship table design, a STOCK table has many occurrences in STOCK_DAILY_RECORD table.


2. Hibernate implementation

Stock.java
public class Stock implements java.io.Serializable {
   ...
   private Set<StockDailyRecord> stockDailyRecords = 
                                  new HashSet<StockDailyRecord>(0);
   ...
StockDailyRecord.java
public class StockDailyRecord implements java.io.Serializable {
   ...
   private Stock stock;
   ...
Stock.hbm.xml
>
     name="com.mkyong.common.Stock" table="stock" ...>
    ...
     name="stockDailyRecords" table="stock_daily_record" fetch="select">
        >
             name="STOCK_ID" not-null="true" />
        >
         class="com.mkyong.common.StockDailyRecord" />
    >
    ...
StockDailyRecord.hbm.xml
>
   name="com.mkyong.common.StockDailyRecord" table="stock_daily_record" ...>
  ...
   name="stock" class="com.mkyong.common.Stock">
        name="STOCK_ID" not-null="true" />
  >
  ...

3. Question …

See this file – “Stock.hbm.xml“.
>
     name="com.mkyong.common.Stock" table="stock" ...>
    ...
     name="stockDailyRecords" table="stock_daily_record" fetch="select">
        >
             name="STOCK_ID" not-null="true" />
        >
         class="com.mkyong.common.StockDailyRecord" />
    >
    ...
If the Set variable (stockDailyRecords) in Stock object is modified, and save the Stock object like following
Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);
Will it update the StockDailyRecord table?
Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?

4. Answer …

“inverse” is controlling the above scenario, to define which side should maintain the relationship.
  • Inverse = false (default) – will execute “update mkyong.stock_daily_record” and update the relationship.
  • Inverse = true – Do nothing.
Got it? May be not, let’s explore more examples to understand about it.

“Inverse = false” example

If no “inverse” keyword is declared, the default is inverse = “false”, which is equal to

...
 name="stockDailyRecords" inverse="false" table="stock_daily_record" ...>
It means both sides are the owner of the relationship. In Hibernate, it will ask both sides to update the foreign key “stock_daily_record.STOCK_ID” in “StockDailyRecord” table.
  • Stock will update the foreign key “stock_daily_record.STOCK_ID” if Set variable (stockDailyRecords) is modified.
  • StockDailyRecord will update the foreign key “stock_daily_record.STOCK_ID” with Stock property as well.

1. Insert example …

Here’s an insert example for inverse=”false”, when a Stock object is saved, Hibernate will generated two SQLSta, one insert and one update.
Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);
Output
Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?)
...
Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?
Stock will update the “stock_daily_record.STOCK_ID” through Set variable (stockDailyRecords), because Stock is the relationship owner.

2. Update example …

Here’s an update example for inverse=”false”, Hibernate will generated three SQL statements, one insert and two updates.
        Query q = session.createQuery("from Stock where stockCode = :stockCode ");
        q.setParameter("stockCode", "4715");
        Stock stock = (Stock)q.list().get(0);
        stock.setStockName("GENM1");
 
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        //set stockDailyRecords data
 
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stockDailyRecords);
        session.update(stock);
Output
Hibernate: 
    insert into mkyong.stock_daily_record (STOCK_ID, ...) 
    values (?, ...)
 
Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?, STOCK_NAME=? 
    where STOCK_ID=?
 
Hibernate: 
    update mkyong.stock_daily_record 
    set STOCK_ID=? 
    where DAILY_RECORD_ID=?
Stock will update the “stock_daily_record.STOCK_ID” through Set variable (stockDailyRecords), because Stock is the relationship owner.
Note
Wait…do you think the third update statement is necessary? The inverse = “true” in Set variable (stockDailyRecords) can stop the Hibernate to generate the unnecessary third update statement.

inverse = “true” example

The inverse=”true” is declared at the Set variable (stockDailyRecords), which means Stock is not the relationship owner, the owner is belong to StockDailyRecord class. In Hibernate, it will enable only the StockDailyRecord class to update the foreign key “stock_daily_record.STOCK_ID” in StockDailyRecord table.

 name="stockDailyRecords" inverse="true" table="stock_daily_record" ...>
  • Stock will not update the foreign key “stock_daily_record.STOCK_ID” if Set variable (stockDailyRecords) is modified.
  • Only StockDailyRecord will update the foreign key “stock_daily_record.STOCK_ID” with Stock property.

1. Insert example …

Here’s an insert example for inverse=”true”, when a Stock object is saved, Hibernate will generated one insert SQL statement.
Stock stock = new Stock();
stock.getStockDailyRecords().add(stockDailyRecords);
session.save(stock);
Output
Hibernate: 
    insert into mkyong.stock (STOCK_CODE, STOCK_NAME) 
    values (?, ?)
Since “Stock” is not the owner of the relationship, it will not update the “stock_daily_record.STOCK_ID” in StockDailyRecord table.

2. Update example …

Here’s an update example for inverse=”true”, Hibernate will generated two SQL statements, one insert and one update.
        Query q = session.createQuery("from Stock where stockCode = :stockCode ");
        q.setParameter("stockCode", "4715");
        Stock stock = (Stock)q.list().get(0);
        stock.setStockName("GENM1");
 
        StockDailyRecord stockDailyRecords = new StockDailyRecord();
        //set stockDailyRecords data
 
        stockDailyRecords.setStock(stock);        
        stock.getStockDailyRecords().add(stockDailyRecords);
 
        session.save(stockDailyRecords);
        session.update(stock);
Output
Hibernate: 
    insert into mkyong.stock_daily_record (STOCK_ID, ...) 
    values (?, ...)
 
Hibernate: 
    update mkyong.stock 
    set STOCK_CODE=?, STOCK_NAME=? 
    where STOCK_ID=?
Since “Stock” is not the owner of the relationship, it will not update the “stock_daily_record.STOCK_ID” in stockDailyRecord table.
inverse vs cascade
Many people like to compare between inverse and cascade, but both are totally different notions, see the differencial here.

Conclusion

Understanding the “inverse” is essential to optimize your Hibernate code, it helps to avoid many unnecessary update statements, which mention in the “update example for inverse=false” above. At last, try to remember the inverse=”true” mean this is the relationship owner to handle the relationship.

Reference

  1. http://www.mkyong.com/hibernate/inverse-true-example-and-explanation/
  2. http://simoes.org/docs/hibernate-2.1/155.html
  3. http://docs.jboss.org/hibernate/stable/core/reference/en/html/example-parentchild.html
  4. http://tadtech.blogspot.com/2007/02/hibernate-when-is-inversetrue-and-when.html






Tuesday, February 1, 2011

File upload with HttpComponents Client 4.0 (successor of Commons HttpClient 3.x)




Background: I’m working on an application that should be able to integrate with various issue trackers (JIRA, Bugzilla, etc.) First I tried using the latest stable branch of Apache Commons HttpClient 3.1 but soon faced problems as JIRA (running on Tomcat) was not able to extract all parameters I was sending with “multipart/form-data” encoding. I’ve found similar problems reports on the Internet but no solution. So, I’ve decided to try the latest HttpComponents Client(4.0-beta2, while core library was 4.0-beta3 at the time of writing) which came with new problems but my form submission and file upload worked at the end. I summarize my experience here.
As soon as I downloaded HttpComponents Client I realized why they changed the name from Commons HttpClient. This is a completely new API! If you already have code that relies on Commons HttpClient you can not easily switch jar file and make some minor changes. Fortunatelly, HttpComponents use different packages so you should be able to keep your HttpClient code and have both versions coexist in the same application without conflicts. However, I can’t resist to mention that HttpComponents API looks to me a bit over-engineered and so low level that it hurts. (But maybe it’s just me being spoiled after a month on Groovy.)
HttpComponents Client still doesn’t have an appropriate documentation and I could not find a single example of file upload that worked for me. So, after mingling my existing code and code from HttpComponents test cases, I’ve finally made a first version that was able to upload file and here’s somewhat simplified version of it:
public void testUpload() throws Exception {
 HttpClient httpclient = new DefaultHttpClient();
 HttpPost httppost = new HttpPost(myUploadUrl);

 MultipartEntity reqEntity = new MultipartEntity(
  HttpMultipartMode.BROWSER_COMPATIBLE);

 reqEntity.addPart("string_field",
  new StringBody("field value"));

 FileBody bin = new FileBody(
  new File("/foo/bar/test.png"));
 reqEntity.addPart("attachment_field", bin );

 httppost.setEntity(reqEntity);

 System.out.println("executing request " + httppost.getRequestLine());
 HttpResponse response = httpclient.execute(httppost);
 HttpEntity resEntity = response.getEntity();

 if (resEntity != null) {
  String page = EntityUtils.toString(resEntity);
  System.out.println("PAGE :" + page);
 }
}
I omit package imports in the example above but I’m sure you’ll manage without it. Notice use ofHttpMultipartMode.BROWSER_COMPATIBLE parameter in line 6. It was crucial for me as upload didn’t work when I used default constructor for MultipartEntity (that initializes entity for the strict multipart mode). With hope that code above is all what’s needed, I made a small change (replacing lines 11-13 above) to upload image from byte array instead from file:
reqEntity.addPart("attachment_field",
  new InputStreamBody(
   new ByteArrayInputStream(imageBytes),
   "image/png", "test.png"));
Surprisingly, this change broke my upload! Again, documentation and googling on this topic didn’t give me any clue on what could be wrong. So, I plunged into HttpComponents source code and found that the major different between the InputStreamBody and FileBody was that methodgetContentLength() of the former was returning -1 (which is somewhat logical but again…). As I already had image as a byte array, content length was known to me. So, I extended InputStreamBody class as follows:
class InputStreamKnownSizeBody extends InputStreamBody {
 private int lenght;

 public InputStreamKnownSizeBody(
   final InputStream in, final int lenght,
   final String mimeType, final String filename) {
  super(in, mimeType, filename);
  this.lenght = lenght;
 }

 @Override
 public long getContentLength() {
  return this.lenght;
 }
}
Now I could use my InputStreamKnownSizeBody class to upload any in-memory file:
reqEntity.addPart("attachment_field",
  new InputStreamKnownSizeBody(
   new ByteArrayInputStream(imageBytes),
   imageBytes.length, "image/png", "test.png"));
At the end, although I’m not delighted with complexities of HttpComponents, it worked for me at the end and I resolved file upload issues I experienced with Commons HttpClient. I hope this post will be of help to someone.
At least few people were struggling with requirement for the MIME library (see bellow discussion). I’ve personally switched to the 4.1 Alpha 2 (the latest version at the time of writing) which removes dependency on org.apache.james.mime4j and comes with ownhttpmime-4.1-xxx.jar library.



Monday, December 27, 2010

Interesting and Clever Facebook Status Messages



Pakistan may not have a Nuclear weapon, but they do have Imran Lakhani, and India cannot produce one. No matter how hard it tries. :)


Imran is Loved by Some, Hated by Many, Envied by Most, Yet Desired by Plenty.


More You Sweat In Peace, Less You Bleed In War.


All the desirable things in Life are either Illegal, Expensive, Fattening or Married to Someone Else.


Good Morning... I see the assassins have failed :)




scratch here ▒▒▒▒▒▒▒▒▒▒▒▒▒▒ to reveal today’s status.




I have an oven with a 'stop time' button. It's probably meant to be 'stop timer' but I don't touch it, just in case. ;)




Har cheez apne waqt par achi lagti hai, naiki karne ka sahi waqt hai "Jawani", hum "Naikiyan" us waqt karte hain jab "Buraiyan" karne ke qabil nahi rehte




Imran is Loading ████████████ 99%




Imran is experiencing life at a rate of several WTF's a minute




Imran is cle'a]ni.ng hi's ke]yb29oa;rd




Imran feels like getting some work done...and so I am sitting down until the feeling passes ;)






There are people who live their whole life in Default settings, never realize they can Customize it.




‎"2 GET & 2 GIVE" creates 2 many problems...
But
(Just double it)
"4 GET & 4 GIVE" solves All the problems...





(URDU)
Har Cheez Apne Waqt Par Achi Lagti Hai.
Naiki Karne ka sahi waqt Jawani Hai.
Hum Naikiyan us waqt Karte Hain, Jab Buraiyan Karne Kay Qabil Nahi Rehte


(ENGLISH)
Everything suits on Time
The Best Time for Good Deeds is Young Age
We do good deeds when we cannot commit more Sins.









Thursday, June 17, 2010

10 HR Interview Tips

The interview process nearly always includes a sit down with human resources as well as your potential future boss and colleagues. The folks in HR don’t know the most about the day-to-day requirements of the position being filled and they’re unlikely to have to deal with whoever gets the gig on a daily basis, so what exactly are they looking for and how do they determine whether you’ve made the cut?

Recently, opinionated blogger and experienced HR pro Laurie Ruettimann gives us job-hunting schmoes a break and offers a peak inside the mind of HR on her blog Punk Rock HR. Her ten tips are a must read for any job-hunter looking to wow human resources in an interview, and is particularly valuable for those new to the interview game.

  • Never badmouth anything or anyone. This applies to your former employer, coworkers, or Osama bin Laden. We’re trying to screen out whiners and troublemakers. I don’t care if your last supervisor was a tyrant. Be kind and magnanimous about everything and everyone.

  • Make sure your appearance is in order. Fair or not, you are judged based you based on how you look. Check your fly and make sure your eyebrows are smooth.

  • Don’t smoke on the day of the interview. We can smell it. We don’t like it. There is an unconscious bias against smokers, and let’s face it, you have a reputation for being lazy. Smokers are more expensive to insure, too. Why would we want you on the payroll? Help me help you. Don’t smoke.

  • Don’t be too aggressive and tell us how awesome you are. You’re here, aren’t you? A little humility, and some self-deprecating comments, will go along way with HR professionals. Trust me.

  • Don’t tell us your life story. We hate it when you confuse HR with your mother, your therapist, or your best friend.

  • Don’t expect us to have a timeline for the interview process. We have no idea how long it will take to fill the position. Ideally, we want to fill the opening tomorrow so we can get back to online shopping. Realistically, it will probably take a few months.

  • Be prepared to talk about your strengths and weaknesses. Don’t ever tell us that you struggle to delegate. You care too much. You take on too much responsibility. An interview is a conversation, not a bad eHarmony profile. Show some self-awareness.

  • When you take us through your resume, don’t gloss over the mistakes. We like it when you stop and tell us about an experience that taught you something. It shows character. Address your flaws outright and tell us how you learned something.

  • Compliment us. Seriously. We are human beings, too. Scan our offices and look for awards, photos, or something noteworthy. Make a connection. This is what salespeople do, and it works. We will remember your praise.

  • Make it easy for us to hire you. When you give us examples during the interview process, frame those examples in a way that relates to the job description, the issues in the industry, or the company’s mission. Be relevant and you will be remembered.

Monday, May 3, 2010

Iterating Over Files and Writing in Another Directory -- Java

Below is the sample code for iterating over all the files in a directory and copying them to another place.


package com.learn;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;


public class CopyFile {

public static void main(String[] args) {
try {
System.out.println("==================");
File dir = new File("/your/directory/path/");

File newDir = new File(dir.getAbsolutePath() + "/copy");
newDir.mkdir();

File[] files = dir.listFiles();
for (File file : files) {
if (!file.isDirectory()) {
FileReader in = new FileReader(file);
FileWriter out = new FileWriter(newDir.getAbsolutePath() + "/" + file.getName());
int c;
while ((c = in.read()) != -1)
out.write(c);

in.close();
out.close();
System.out.println(file.getName() + " is copied ");
}
}
System.out.println("==================");
} catch (Exception e) {
e.printStackTrace();
}
}

}

Wednesday, April 28, 2010

Hudson Address Bind Issue (java.net.BindException: Address already in use)

Hudson is a great software tool, but unfortunately yesterday as soon as I updated my hudson WAR, it stopped working and keeps giving me error below.

java.net.BindException: Address already in use
at java.net.PlainDatagramSocketImpl.bind0(Native Method)
at java.net.PlainDatagramSocketImpl.bind(PlainDatagramSocketImpl.java:82)
at java.net.DatagramSocket.bind(DatagramSocket.java:368)
at java.net.MulticastSocket.(MulticastSocket.java:147)
at java.net.MulticastSocket.(MulticastSocket.java:112)
at hudson.UDPBroadcastThread.(UDPBroadcastThread.java:58)
at hudson.model.Hudson.(Hudson.java:606)
at hudson.WebAppMain$2.run(WebAppMain.java:224)

It happens due to previous hudson application failed to close the port 33848.

It took my 2 hours but finally i was able to find the solution.

This is the line that saves my life :)
-Dhudson.udp=33849

Solution is the simple below line that need to be added in your tomcat's catalina.sh.

JAVA_OPTS="$JAVA_OPTS -Dhudson.udp=33849"


Reference: http://issues.hudson-ci.org/browse/HUDSON-5177

HTTP Clent 4 HTTP PUT Multipart Client Code Sample

Few days back got stuck in usage of HTTP Client 4.0 Library usage for Multi Part Put Request.
Finally found a workaround and thought to share with everyone.

Below is the Sample code.


import java.io.File;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;


public class PutRequestTest {

public static void main(String[] args) {
try {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);

HttpPost method = new HttpPost("http://localhost:8080/AdamService/service/sharedshelf/json/insertImage");

File file = new File("/Users/imranlakhani/a.JPG");
MultipartEntity mp = new MultipartEntity();
mp.addPart("projectId", new StringBody("1234", Charset.forName("UTF-8")));
mp.addPart("Name", new StringBody("image.jpg", Charset.forName("UTF-8")));
mp.addPart("username", new StringBody("imran", Charset.forName("UTF-8")));
mp.addPart("instituteId", new StringBody("2", Charset.forName("UTF-8")));
mp.addPart("password", new StringBody("", Charset.forName("UTF-8")));
FileBody fileBody = new FileBody(file);
mp.addPart("File", fileBody);
method.setEntity(mp);

System.out.println("executing request " + method.getRequestLine());
HttpResponse response = httpclient.execute(method);
HttpEntity resEntity = response.getEntity();

System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}

httpclient.getConnectionManager().shutdown();

} catch (Exception e) {
e.printStackTrace();
}

}
}