August 02, 2015

SpringMVC: PropertyPlaceHolder

Another interesting support feature provided by Spring is using properties in your code through PropertyPlaceholderConfigurer. It helps load application properties from either a file or database table. The XML for using both,which will go into your spring context file,is 

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="properties">
        <bean class="org.apache.commons.configuration.ConfigurationConverter"
             factory-method="getProperties">
                 <constructor-arg>
                   <bean class="org.apache.commons.configuration.DatabaseConfiguration">
                          <constructor-arg ref="<database bean>" />
                          <constructor-arg value="<database property table>" />
                          <constructor-arg value="<tablecolumn for placeholdernames>" />
                          <constructor-arg value="<tablecolumn for placeholdervalues>" />
                   </bean>
                </constructor-arg>
        </bean>
     </property>
     <property name="locations">
         <list>
            <value>file:src/main/webapp/WEB-INF/application.properties</value>
         </list>
     </property>
</bean>

<constructor-arg value="datasource" /> refers to a database bean defined in the spring context xml.

<constructor-arg value="app_config" /> refers to a database table APP_CONFIG.

<constructor-arg value="config_key" /> refers to column 'CONFIG_KEY' in APP_CONFIG that will contain the property you want to use in your code.

<constructor-arg value="config_value" />  refers to column 'CONFIG_VALUE' in APP_CONFIG that will contain the corresponding value of the property.


The below example shows how to then use the pre-loaded properties in your Spring code.


@Controller
public class DocumentController{

     @Value("${doc_Base}")
      String docBase="";
      @Value("${app_Env}")
      String appEnv=null;
      @Value("${doc_Path}")
      String docPath="";

      @Autowired
      private DocumentDAO documentDao;

      @Autowired
      private UserDAO userDao;

      @RequestMapping(value="/upload")
      public String uploadDocument(@RequestParam("docName)String documentName,
                                  @RequestParam("docFile")MultipartFile file)
      {
         <upload logic>

     }
       

}

The members docBase,appEnv & docPath will be initialized when the Controller instance gets created. Here doc_Base,app_Env & doc_Path are property names defined in CONFIG_KEY & their corresponding values in CONFIG_VALUE will be used for initialization

CONFIG_KEY       CONFIG_VALUE
doc_Base              test
app_Env               Dev
doc_Path              /dev/reviews



References

http://forum.spring.io/forum/spring-projects/container/82142-propertyplaceholderconfigurer-problems

July 04, 2015

Spring MVC: PagedListHolder



Spring 3 MVC framework provides supporting classes/annotations that can prove to be real "gems" during development of your web application. I'll be covering a few of them, the first being "PagedListHolder".


PagedListHolder


Spring Framework comes with a bean called org.springframework.bean.support. PagedListHolderAs per documentation, PagedListHolder is a simple state holder bean for handling lists of objects, separating them into pages. It has setter methods to indicate page size, page number.

For e.g in your specific Controller class you can add the following code snippet to create paginated data that can be accessed in a JSP or any other View.



 


String srchkey= request.getParameter("srchkey");
if (srchkey!= null) 
{
 PagedListHolder<Product> productList = new PagedListHolder<Product>(getProductList(srchkey)); 
productList.setPage(0);
        productList.setPageSize(4);        request.getSession().setAttribute("productList", productList); 
        return new ModelAndView("ListProducts", "productList", productList);    
}
else 
{ 
        String page = request.getParameter("page"); 
        PagedListHolder productList = (PagedListHolder)request.getSession().getAttribute("productList"); 

        if ("next".equals(page)) 
            productList.nextPage(); 

        else if ("previous".equals(page))
            productList.previousPage();
       
        return new ModelAndView("ListProducts", "productList", productList);    
}




References

http://stackoverflow.com/questions/2245035/how-to-implement-pagination-in-spring-mvc-3




Use AJAX to access JSON from a Struts2 Action class



If there is a use-case wherein a HTTPRequest invokes a Struts2 Action class to perform an action & its output is then to be received by an AJAX function on the target webpage, for e.g.population of data rows in an HTML table, then this is one approach to do it

1. Send the output of the Struts2 Action class as a JSON object. 


 Let's say we have an Action class 'JSONResponseAction.java' that is required to send a Java bean 'ResponseVO.java' ( it has 2 String fields- a status & a message) as a JSON object to client e.g a browser. 

public class JSONResponseAction extends BaseActionSupport
{

public ResponseVO responsVO;


public String load() throws IOException, ServletException
{
   
responseVO=new ResponseVO();
responseVO.setStatus("success");
responsVO.setMessage("Process completed");

}

public ResponseVO  getResponseVO() 
{
    return responseVO;
}

public void setResponseVO(ResponseVO responseVO) 
{
    this.responseVO= responseVO;
}

}

It is mandatory that setter & getter methods be present for 'ResponseVo' bean in the Action class for corresponding JSON object to be created & sent across the n/w. We can also use the default 'execute()' method of Struts2 Action class for this. In that case,We will not have to explicitly mention the method-name in the request URL in pt.3

2. In the struts.xml, we define an action 'JSONResponseAction.action' as follows

  <action name="JSONResponseAction"  class=JSONResponseAction>
  <result name="success" type="json">
     <param name="root">
             responseVO
  </param>
  <result name="failure">/error.jsp</result>
  <interceptor-ref name="defaultStack"/>
 </action>


3. On the client side, we can have JQuery code, something similar to what I have written below, to access 'ResponseVO'.



$.getJSON( "${pageContext.request.contextPath}/JSONResponseAction.action?method:load",
{<requestparamName>:<requestParamvalue>},
function(responseVO) {

     //Jquery or Javascript code to use 'ResponseVO'


});

4. We can also send an array of 'ResponsVO' beans in a similar fashion

public class JSONResponseAction extends BaseActionSupport
{

public ResponseVO[] responseVO;

public String load() throws IOException, ServletException
{
  //populate the array

}
public ResponseVO[]  getResponseVO() 
{
    return responseVO;
}

public void setResponseVO(ResponseVO[] responseVO) 
{
    this.responseVO= responseVO;
}

}


April 23, 2015

CallableStatement.setObject() SQLException - Fail to construct descriptor: Invalid arguments


Oracle supports structured user-defined types or UDTs.  JDBC 2.0 provides an ability to custom map a Oracle UDT using a Java class. The class will have a field for each attribute in the UDT. The class has to implement java.sql.SQLData  & Serializable interfaces. There are other techniques available such as the ORAData and ORADataFactory interfaces provided by Oracle but this post deals with SQLData.

Let's say, you have a UDT  'OBJ_USER' that has the following attributes - userid, username and corresponding Java mapper class called UserObj.java

CREATE OR REPLACE TYPE OBJ_USER
  (
    USERID NUMBER,
    USERNAME VARCHAR(40)    
  );

public class UserObj implements SQLData,Serializable {

     private long userID;
     private String userName;
    private String sql_type;
}


Now we can persist & read data using UDT and its corresponding Java mapper object. The 'SQLData' interface provides two methods for this

@Override
public void writeSQL(SQLOutput stream) throws SQLException 
{
    stream.writeLong(userId);            
    stream.writeString(userName);
             
 }

@Override
public void readSQL(SQLInput stream,String typethrows SQLException 
{
    sql_type= type;
    userId=stream.readLong();            
    userName=stream.readString();
             
 }


The following code calls a StoredProcedure using a JDBC CallableStatement instance that will persist the UDT data to a table ( We don't need to worry about that since  focus here is the JDBC approach to map data)


conn =  createConnection();
String schname = <SCHEMA>;
             
System.out.println("conn::" + conn);
Map map = conn.getTypeMap();
System.out.println("SchemaName:" + conn.getMetaData().getUserName());
map.put(schname + ".OBJ USER", Class.forName("UserObj"));
                                 
cstmtForCMValidation = conn.prepareCall("{call <package_name>.<procedure_name>(?,?,?)}");
cstmtForCMValidation.setObject(1, userObj);                                                                                                          

However, 'setObject(1, userObj)' call can throw the following exception

java.sql.SQLException: Fail to construct descriptor: Invalid arguments
       at oracle.jdbc.driver.SQLStateMapping.newSQLException(SQLStateMapping.java:70)
       at oracle.jdbc.driver.DatabaseError.newSQLException(DatabaseError.java:133)
       at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:199)
       at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:263)
       at oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:271)
       at oracle.sql.StructDescriptor.createDescriptor(StructDescriptor.java:161)
       at oracle.sql.StructDescriptor.createDescriptor(StructDescriptor.java:137)
       at oracle.sql.STRUCT.toSTRUCT(STRUCT.java:477)
       at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:7954)
       at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:7547)
       at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:8037)
       at oracle.jdbc.driver.OracleCallableStatement.setObject(OracleCallableStatement.java:4132)
       at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:238)


To fix this exception, the 'UserObj.java'  field - sqltype  will have to be set with UDT name either in the constructor or its setter e.g

 public UserObj (){
   sql_type=SCHEMA+".OBJ_USER";
}

Note: this field has to be set with the fully qualified name of the UDT i.e. with DB schema name

This is because while writing data from the mapper object to the UDT, CallableStatement instance will not look for mapping relation in the 'Type' Map of JDBC Connection object. It will check the value of sqltype field of mapper object.

February 26, 2015

AbstractAnnotationConfigDispatcherServletInitializer conflict with web.xml for Spring Security


When we use Spring Security in our application, we  extend 
AbstractAnnotationConfigDispatcherServletInitializer 
to include our WebSecurityConfigurerAdapter implementation into the root context.


However this can throw the following error during application startup

"Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your webxml!"

One reason the above may happen is because we could be having the following snippet in our web.xml

<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param> 

which already creates the root context for the Application from
/WEB-INF/applicationContext.xml.


Servlet 3.X specification allows us to do away with XML and create Java-based configuration. So we can comment the above snippet in web.xml and add the following method in our AbstractAnnotationConfigDispatcherServletInitializer subclass to remove the above error.


@Override
protected WebApplicationContext createRootApplicationContext() {
// TODO Auto-generated method stub
return new XmlWebApplicationContext();
}

The no-arg XmlWebApplicationContext instance uses
"/WEB-INF/applicationContext.xml" by default.