Tuesday, March 24, 2009

iBATIS Parameter Maps (a.k.a my iBATIS brain f*rt)

Problem:
On a project using iBATIS, I was receiving the following stacktrace:

stacktrace
org.springframework.dao.TransientDataAccessResourceException: SqlMapClient operation; SQL [];  
--- The error occurred in {myproject}/PlanningProject.xml. 
--- The error occurred while applying a parameter map. 
--- Check the {myparametermap}  
--- Check the parameter mapping for the 'startDate' property.  

--- Cause: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:   
--- The error occurred in com/kpe/resourcePlanning/domain/dao/ibatis/PlanningProject.xml. 
--- The error occurred while applying a parameter map. 
--- Check the {myparametermap}  
--- Check the parameter mapping for the 'startDate' property.  
--- Cause: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).


And this is the snippet of the parameter map that is significant:

PlanningProject.xml
  <parameterMap id="updatePmap" class="PlanningProject">
    <parameter property="startDate" jdbcType="TIMESTAMP" javaType="org.joda.time.LocalDate" typeHandler="com.kpe.resourcePlanning.domain.dao.ibatis.TypeHandlerCallbackLocalDate" />
    <parameter property="endDateConstraint" jdbcType="TIMESTAMP" javaType="org.joda.time.LocalDate" typeHandler="com.kpe.resourcePlanning.domain.dao.ibatis.TypeHandlerCallbackLocalDate" />     
    <parameter property="modifiedBy" jdbcType="VARCHAR" />
    <parameter property="id" jdbcType="NUMBER" />
  </parameterMap>

  <update id="update" parameterMap="updatePmap">
    UPDATE resourcePlanning.planningproject
    SET 
        startDate = #startDate#,
        endDateConstraint = #endDateConstraint#,
        modifiedBy = #modifiedBy#,
        modifiedDate = now() 
    WHERE 
        projectId = #id#
  </update>



Well, my project hardly ever used explicit parameter maps. Usually, statements used the parameterClass="" syntax. So, as you might already know, my syntax was terribly wrong. The correct syntax follows. The thing to note (at least for me) is that the order of the individual SET parameters must match the order given in the parameter map that you use.



  <parameterMap id="updatePmap" class="PlanningProject">
    <parameter property="startDate" jdbcType="TIMESTAMP" javaType="org.joda.time.LocalDate" typeHandler="com.kpe.resourcePlanning.domain.dao.ibatis.TypeHandlerCallbackLocalDate" />
    <parameter property="endDateConstraint" jdbcType="TIMESTAMP" javaType="org.joda.time.LocalDate" typeHandler="com.kpe.resourcePlanning.domain.dao.ibatis.TypeHandlerCallbackLocalDate" />     
    <parameter property="modifiedBy" jdbcType="VARCHAR" />
    <parameter property="id" jdbcType="NUMBER" />
  </parameterMap>

  <update id="update" parameterMap="updatePmap">
    UPDATE resourcePlanning.planningproject
    SET 
        startDate = ?,
        endDateConstraint = ?,
        modifiedBy = ?,
        modifiedDate = now() 
    WHERE 
        projectId = ?
  </update>

Monday, March 23, 2009

Animate Your Page During Confirmation

Problem:
I desired the following feature on my page. When the user clicked a link, do the following:
  1. Use scriptaculous animations to "get rid of" the current page (goal is to eliminate other links and form submit buttons and provide visual feedback that a 'process' has started).
  2. Display the dialog that was *already* coded into the link's onclick event.
  3. If they choose 'ok', give them visual feedback that the action has been submitted and then *continue* to the link destination.
  4. If they choose 'cancel', restore the page.

Solution: yourpage.jsp
Event.observe( window, 'load',
  function() {
      //alert('observing window load');

      $$('.processRole').each(

          function(value, index) {
              var old = value.onclick;

              value.onclick = function() {

                  new Effect.SlideUp('pagecontent', {
                      duration: 1.0,
                      queue: 'front'
                  });

                  new Effect.Fade('copyRight', {
                      duration: 1.0,
                      queue: 'end',
                      afterFinish: function(o) {
                          var rv = old.call(value);

                          if (rv) {
                              // alert('you chose ok');

                              new Effect.Appear('waitNotification', {
                                  queue: 'end'
                              });

                              new Effect.Highlight('waitNotification', {
                                  queue: 'end'
                              });
                           
                              new Effect.Appear('copyRight', {
                                  queue: 'end'
                              });                              

                              location.href = value;

                          } else {
                              //alert('you chose cancel');

                              new Effect.SlideDown('pagecontent', {
                                  duration: 1.0,
                                  queue: 'front'
                              });
                            
                              return false; // this return doesn't have any effects currently
                          };

                      }

                  });
                            
                  return false; // always return false
              };

          }
      );      
  }

);


A slight improvement; do not begin the navigation until the last animation is finished:
snippet: yourpage.jsp
                         
new Effect.Appear('copyRight', { 
    queue: 'end',
    afterFinish: function(o) {
     location.href = value;
    }
});

//location.href = value;

Tuesday, March 17, 2009

iBATIS Datasource Configuration (plus Spring)

On a project, we originally used iBATIS "raw" and had the prototypical datasource defined like this:


sqlMap.xml
    <transactionManager type="JDBC">     
<dataSource type="SIMPLE">
<property name="JDBC.Driver" value="${ibatis.mysql.driver}"/>
<property name="JDBC.ConnectionURL" value="${ibatis.mysql.url}/resourcePlanning" /> jdbc:mysql://localhost:3306/powerSource" />
<property name="JDBC.Username" value="${ibatis.mysql.user}"/>
<property name="JDBC.Password" value="${ibatis.mysql.password}"/>

<property name="Pool.PingQuery" value="select 1"/>
<property name="Pool.PingEnabled" value="true"/>
<property name="Pool.PingConnectionsOlderThan" value="${ibatis.timeout}"/>

</dataSource>
</transactionManager>

Upon improving our application architecture to use true DAOs, we concurrently upgraded to use Spring DI in our web app and subsequently took advantage of using Spring 'template' wrappers. However, changing the configuration was quite a lesson learned on my part:

Step 1: Remove transactionManager from iBATIS

Step 2: Create new 'datasource' bean using Spring
spring.xml
    <bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource">
<property name="url" value="${ibatis.mysql.url}/resourcePlanning"/>
<property name="username" value="${ibatis.mysql.user}"/>
<property name="password" value="${ibatis.mysql.password}"/>
<property name="driverClassName" value="${ibatis.mysql.driver}"/>


<property name="testWhileIdle" value="true"/>
<property name="validationQuery" value="select 1"/>

<property name="logAbandoned" value="true"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="3600"/>

<property name="maxWait" value="20"/>
<property name="maxIdle" value="10"/>
<property name="maxActive" value="-1"/>

</bean>


Step 3: Create new Spring-wrapped SqlMapClient using new 'datasource' bean

spring.xml
    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation">
<value>classpath:com/kpe/resourcePlanning/domain/dao/ibatis/sqlMap.xml</value>
</property>

<property name="transactionConfigClass">
<value>com.ibatis.sqlmap.engine.transaction.jdbc.JdbcTransactionConfig</value>
</property>

<property name="dataSource">
<ref bean="dataSource"/>
</property>

</bean>

Thursday, March 12, 2009

Struts Multibox

This is going to be a useless post if I do not remember to get back to this, but I created a rather elegant way of doing checkboxes in tables (displaytag none-the-less) so that Struts 1.x actions could easily get the objects to which they refer.

Stay tuned...