Oct 8, 2011

extjs working with servlet



Following are the steps to delegate ExtJS Ajax or any synchronous calls to servlet.

1). Create a servlet class, with minimum having its doPost and doGet method. I have annotated the servlet with spring’s Controller annotation, which helps me later in doPost processing, but doesn’t impact much for processing at servlet level. You may opt for not to annotate with @Controller and use a simple HttpServlet. Below is full servlet code   

    import java.io.PrintWriter;
     import java.util.Enumeration;
     import java.util.List;
     import javax.servlet.http.HttpServlet;
     import javax.servlet.http.HttpServletRequest;
     import javax.servlet.http.HttpServletResponse;
     import org.springframework.stereotype.Controller;
     import net.sf.json.JSONArray;
     import com.ecms.model.Mainjob;
     import com.ecms.service.MainjobService;
@Controller
public class TestServlet extends HttpServlet {
     private MainjobService mainjobService;
     List<Mainjob> mainjobs = null;
     @Override
     public void doPost(HttpServletRequest req, HttpServletResponse res){
           try{
           System.out.println("inside doPost");
           System.out.println("going to get req params doPost");
           Enumeration<String> param = req.getParameterNames();
           String temp;
           while (param.hasMoreElements()){
                temp = param.nextElement();
           System.out.println("req-->>"+temp+"--value-"+req.getParameter(temp));
           }
           System.out.println("got params ererere");
           // Json object form of data
           String data = "{total:     4," +
                     "data: "+"[ {jobno: \"1\", eta: \"2\", portloading: \"Sin\", flightno: \"1243\"}," +   "          {jobno: \"2\", eta: \"2\", portloading: \"Sin\", flightno: \"14334\"}," +
        "          {jobno: \"3\", eta: \"2\", portloading: \"Sin\", flightno: \"233\"}," +
                     "          {jobno: \"4\", eta: \"2\", portloading: \"Sin\", flightno: \"1233\"}" +"]}";
           PrintWriter out = res.getWriter();
           out.print(data);
           JSONArray jsonArray = JSONArray.fromObject(mainjobs);
           System.out.println("jsonArray"+jsonArray);
           System.out.println("mainjob size-->>"+mainjobs.size());
           System.out.println("data--"+data);
           }
           catch(Exception ex){
                ex.printStackTrace();
           }
     }
     @Override
     public void doGet(HttpServletRequest req, HttpServletResponse res){
           System.out.println("inside doGet");
     }
}





2) Declare this servlet class in application’s web.xml. Following is how I modify my web.xml.

 <servlet>
           <servlet-name>test-servlet</servlet-name>
           <servlet-class>com.ecms.dao.test.TestServlet</servlet-class>
           <load-on-startup>1</load-on-startup>
     </servlet>
     <servlet-mapping>
           <servlet-name>test-servlet</servlet-name>
           <url-pattern>*.test</url-pattern>
     </servlet-mapping>


3) Now update the JS file to point the call to the particular URL mentioned in the web.xml, if you use proxy within the JS file, than proxy’s api must now use any url that has suffix as “.test” as we have mapped test servlet to “/*.test” URL in application’s web.xml file (step2). Following is the code segment, where I integrate the call which forward to servlet.

var proxy = new Ext.data.HttpProxy({
        api: {
            read : 'mainjob/viewMainjob.test',
            create : 'mainjob/createMainjob.action',
           }
    });

Note the difference between read and create, both URL has different suffix.

Above shows that the read operation would delegate task to test servlet, and create operation would look for “.action” mapping in web.xml, which can be mapped to another servlet.

Hope its useful for you, drop me your queries if any.

Thanks

Oct 4, 2011

JPA composite primary key example

JPA composite primary key requires careful implementation of Entity’s ID class,

There are two ways of it mentioned in JPA documentations

1)      Using Embeddable Composite Primary Key Class (uses @ Embeddable annotation)
2)      Using Non-Embedded Composite Primary Key Class (uses IDClass annotation from JPA)

Both above mentioned approaches are easy to implement, I anyhow selected second approach to work with in my project.

Following are the steps to implement


1) Created an Entity Class say Customer, which I annotated with @Entity annotation from JPA.

My Customer class looks like as given below:






@Entity
@Table(name="customer")
public class Customer implements Serializable {
     private static final long serialVersionUID = 1L;
    
     @Id
     @Column(name ="name")
     private Integer customerName;
     @Id
     @Column(name = "customer_id")
     private Integer customerId;
   
     /**
      * @return the customerId
      */
     public Integer getCustomerId() {
           return customerId;
     }
     /**
      * @param customerId the customerId to set
      */

     public void setCustomerId(Integer customerId) {
           this.customerId = customerId;
     }

     /**
      * @return the customerName
      */

     public Integer getCustomerName() {
          return customerName;
     }
     /**
      * @param customerName the customerName to set
      */
     public void setCustomerName(Integer customerName) {
           this.customerName = customerName;
     }
}




I have annotated both customerName and customerId with @Id, and Customer class with @Entity annotation.

3)   As we have a composite primary key for Customer Entity, so it requires for us to have an IDClass which mentions both the keys as parameters.
4)      I constructed the required ID class as given below




public class CustomerCompositeKey {
     private Integer customerName;
     private Integer customerId;
}




While testing above composite key, we will surely get some exception it doest not look complete and compliance with JPA documentation,  anyhow I run the test to retrieve data from database and got the following exception

Exception in thread "main" java.lang.IllegalArgumentException: to.CustomerCompositeKey cannot be cast to java.io.Serializable
       at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:191)
       at mgr.CustomerMgr.getCustomer(CustomerMgr.java:24)
   at Test.main(Test.java:51)


Above exception caused by the not having Serialization interface implementation with my Composite key

So I changed my class further

public class CustomerCompositeKey implements Serializable{
    
     private static final long serialVersionUID = 1L;

If you follow the JPA document, they mention following rules for Composite key class link

·  Must be a POJO class, with public access and with a public constructor.
· properties of composite primary key class must be public or protected.
·  Serializable; and having implementation of  equals and hashCode methods.

Upon applying following changes my composite key evolved further as given below

/**

 *
@author varun

 *

 */

public class CustomerCompositeKey implements Serializable{
     private static final long serialVersionUID = 1L;
     public  String customerName;
     public  Integer customerId;
     public CustomerCompositeKey(){
     }
     public CustomerCompositeKey(String name, Integer id){
           this.setCustomerId(id);
           this.setCustomerName(name);
     }
     /**
      * @return the customerName
      */
     public String getCustomerName() {
           return customerName;
     }
     /**
      * @param customerName the customerName to set
      */
     public void setCustomerName(String customerName) {
           this.customerName = customerName;
     }
     /**
      * @return the customerId
      */
     public Integer getCustomerId() {
           return customerId;
     }
     /**
      * @param customerId the customerId to set
      */
     public void setCustomerId(Integer customerId) {
          this.customerId = customerId;
     }
     public int hashCode() {
        return (int) customerId.hashCode();
    }
   public boolean equals(Object obj) {
        if (obj == this) return true;
        if (!(obj instanceof ConfigNodeTypeId)) return false;
        if (obj == null) return false;
        CustomerCompositeKey pk = (CustomerCompositeKey) obj;
        return pk.customerId.equals(customerId);
    }
}



Upon testing, it throws another exception, which says

Exception in thread "main" java.lang.IllegalArgumentException: Provided id of the wrong type. Expected: class java.lang.String, got class to.CustomerCompositeKey
       at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:188)
       at mgr.CustomerMgr.getCustomer(CustomerMgr.java:24)
   at Test.main(Test.java:51)

This is actually taking the default type of parameter for Customer entity instead of a composite key to match and find the record, this is because we have forgotten the very important step of including @IDClass annotation to bind the Entity to ID Class or composite key.

We further modify our Customer Entity class as

@Entity
@IdClass(CustomerCompositeKey.class)
@Table(name="customer")
public class Customer implements Serializable {
..
..

Upon testing further following Exception printed


 [ WARN][org.hibernate.util.JDBCExceptionReporter:71]SQL Error: 1054, SQLState: 42S22
[ERROR][org.hibernate.util.JDBCExceptionReporter:72]Unknown column 'customer0_.customerName' in 'field list'
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not load an entity: [to.Customer#component[customerName,customerId]{customerName=null, customerId=null}]
       at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:647)
       at org.hibernate.ejb.AbstractEntityManagerImpl.find(AbstractEntityManagerImpl.java:194)
       at mgr.CustomerMgr.getCustomer(CustomerMgr.java:24)
   at Test.main(Test.java:51)


This is found to be strange, even after following all the steps mentioned by JPA documentation, still there is trap.

Actually it says the particular column are not in the table, or your key’s entity names are not matching with your column, any way change the names to  matching your table column than you also have to change the names in the Entity class. But simpler solution is to annotate your IDClass or composite key attributes with @Column and in the name, write your database column name which are also mentioned in the Entity class.


Here is the updated code for CustomerCompositKey.class






public class CustomerCompositeKey implements Serializable{
     private static final long serialVersionUID = 1L;
     @Column(name ="name")
     private String customerName;
     @Column(name = "customer_id")
     private Integer customerId;
     .. .. ..
     .. .. ..


This would make it finally run and achieve the desired results.

Hope above explanation clears all doubts of composite key in JPA, queries are welcomed.

Thanks