Tuesday, April 14, 2009

Crystal Reports IllegalStateException

So, my companies web app was throwing this nebulous IllegalStateException exception (see stacktrace below) that did not seem to adversely affect the application but I just couldn't let it go. I was able to resolve it like this:
  1. First, I googled it... not much help in the first few pages other than telling me what I already knew. 'out' was being called after it had been commited/closed.
  2. Though I usually don't have to do this anymore, it finally dawned on me to look at the compiled JSP code. (This was legacy, pure JSP... no struts nor nothing.) We were using Tomcat 5.5 and Eclipse 3.3+ so my JSP class was in the 'work' directory of my Eclipse project. Sure enough, there were out.print("") in my compiled JSP class. Where were they coming from?
  3. We had no explicit out.print() in our JSP code, so just looking at where they were in the class and how our JSPs were constructed, it seemed a close correspondence to an out reference for every JSP directive (like @page, etc.)
  4. So, I googled this: illegalstateexception crystal tomcat
    and came across this link http://www.forumtopics.com/busobj/viewtopic.php?t=126993&sid=2b09528912043e0fbe72e0a947dc300a which basically tells you to avoid line breaks between your JSP directives.
  5. Problem solved.


|ESD|13:28:22,363|ERROR|Servlet.service() for servlet jsp threw exception [http-12080-Processor22|org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/esd].[jsp]]
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:607)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:196)
at org.apache.jasper.runtime.JspWriterImpl.initOut(JspWriterImpl.java:125)
at org.apache.jasper.runtime.JspWriterImpl.flushBuffer(JspWriterImpl.java:118)
at org.apache.jasper.runtime.PageContextImpl.release(PageContextImpl.java:179)
at org.apache.jasper.runtime.JspFactoryImpl.internalReleasePageContext(JspFactoryImpl.java:116)
at org.apache.jasper.runtime.JspFactoryImpl.releasePageContext(JspFactoryImpl.java:76)
at org.apache.jsp.pages.reports.CrystalReportViewer_jsp._jspService(CrystalReportViewer_jsp.java:184)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:269)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:215)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:188)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:172)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:174)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:875)
at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:689)
at java.lang.Thread.run(Thread.java:595)

Wednesday, April 8, 2009

Script your ODBC Data Sources (MySQL)

Ok... admittedly this has to do with Windows scripting and not Java nor Javascript but is something that affects many of my projects. If your computer needs ODBC Data Sources, you can script their creation (particularly useful for configuring new developers' computers).

This script should provide a fairly useful start to customizing your own version. I am going to assume that it is fairly self-explanatory but you can always post a response if you do not agree or have a question.


'================================================================
' This script creates one or more ODBC Data Sources.

' Usage: >cscript crystal.odbc.test.vbs
'
' Notes:
' * Search for 'configure-here' for all customization options
'================================================================
Const HKEY_LOCAL_MACHINE = &H80000002

strPrefix = "winmgmts:{impersonationLevel=impersonate}!\\"
strComputer = "."
strSuffix = "\root\default:StdRegProv"
strObjRef = strPrefix & strComputer & strSuffix ': wscript.echo strObjRef
Set objReg = GetObject(strObjRef) 'The Set keyword is mandatory

DriverNames = Array("SQL Server", "MySQL ODBC 3.51 Driver") 'Generally, do not modify these
Drivers = Array("C:\WINDOWS\System32\SQLSRV32.dll", "C:\WINDOWS\system32\myodbc3.dll") 'Generally, do not modify these
'================================================================
' Configuration Section
'================================================================
Const Chosen = 1 'configure-here: Zero-based index into the following two arrays; i.e. which DB are you using
Const Server = "xxxwebtest" 'configure-here: the machine where the DB is hosted
Const Port = "3307" 'configure-here: the port where the DB is hosted
Const Uid = "root" 'configure-here: the username to the DB
Const Pwd = "admin" 'configure-here: the password to the DB
ConnectionList = Array("dbone", "dbtwo", "etcetera") 'configure-here: see Note 1 below

REM *** Note 1 *** This is the array of ODBC Names which you will be creating;
REM also is the name of the database which the odbc connects to
'=== End : Configuration Section ================================

for each connection in ConnectionList
wscript.echo "*** Start *** Creating ODBC Data Source: " & connection

' *** Step 1 *** Create new Data Source Entry in system folder ...\ODBC Data Sources
strKeyPath = "SOFTWARE\ODBC\ODBC.INI\ODBC Data Sources"
strValueName = connection
strValue = DriverNames(Chosen)
call WriteToRegistry

' *** Step 2 *** Create Data Source configuration in new user-defined folder {connection}
strKeyPath = "SOFTWARE\ODBC\ODBC.INI\" & connection
objReg.CreateKey HKEY_LOCAL_MACHINE,strKeyPath

' *** Step 2a *** Database
strValueName = "DATABASE"
strValue = connection
call WriteToRegistry

' *** Step 2b *** Driver
strValueName = "DRIVER"
strValue = Drivers(Chosen)
call WriteToRegistry

' *** Step 2c *** Server
strValueName = "SERVER"
strValue = Server
call WriteToRegistry

' *** Step 2d *** Port
strValueName = "PORT"
strValue = Port
call WriteToRegistry

' *** Step 2e *** UID
strValueName = "UID"
strValue = Uid
call WriteToRegistry

' *** Step 2f *** PWD
strValueName = "PWD"
strValue = Pwd
call WriteToRegistry

' *** Step 2g *** Trusted_Connection : SQL Server only?
strValueName = "Trusted_Connection"
strValue = "Yes"
' call WriteToRegistry

' *** Step 2h *** Description
strValueName = "DESCRIPTION"
strValue = "EditMeThroughRegEdit"
call WriteToRegistry

wscript.echo "*** Finished *** Creating ODBC Data Source.\n"
next 'connection
'===== End of Script =====

'================================================================
' Subroutines and Functions
'================================================================
Sub WriteToRegistry
Const debugDesired = false
If debugDesired Then
wscript.echo "Simulating name/value to: HKEY_LOCAL_MACHINE\" & strKeyPath & ": " & strValueName & "/" & strValue
Else
wscript.echo "Modifying name/value to: HKEY_LOCAL_MACHINE\" & strKeyPath & ": " & strValueName & "/" & strValue
objReg.SetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
End If
End Sub

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...

Thursday, January 22, 2009

"More" Dynamic Forms with Struts

The goal behind this pot-pourri of code snippets is that I had a
spreadsheet-like form whose purpose was to collect information that was
relative to the time/date when the form was being viewed (i.e. "dynamic").
Hopefully, someday I will get the time to cohesively explain the relationship
between the code snippets but they should prove of some value in the meantime.


Reference

http://markmail.org/message/557ico53ydq2gvsp#query:using%20a%20map%20in%20a%20dynaactionform+page:1+mid:557ico53ydq2gvsp+state:results

On Sun, 1 Dec 2002, Martin Cooper wrote:

Date: Sun, 1 Dec 2002 22:18:05 -0800 (PST)
From: Martin Cooper Reply-To: Struts Developers List
To: stru...@jakarta.apache.org
Subject: Using a property of type Map in a DynaActionForm

As far as I can determine, it is not possible to create a DynaActionForm which
has a property of type Map. It is also not possible to extend it to be able
to accept a property of type Map. This seems like an unfortunate omission,
so I'd like to fix it.

First, though, I'd like to get some feedback on whether there is a reason
it's not currently supported, and on the best way of resolving it.

It's *supposed* to work if you declare the property type to be java.util.Map
instead of a concrete implementation of Map. You'll still need to create
your own Map instance at the moment -- I do mine in a custom reset() method,
but we probably also need a better solution based on an initial expression.

Craig




Custom Struts Action Form

package mypackage;

import java.util.HashMap;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.DynaActionForm;

@SuppressWarnings("serial")
public class ActionFormRoles extends DynaActionForm {

@SuppressWarnings("unchecked")
public void reset(ActionMapping mapping, HttpServletRequest request) {
this.getMap().put("roleMap", new HashMap());
this.getMap().put("assignMap", new HashMap());

super.reset(mapping, request);
}

public void reset(ActionMapping mapping, ServletRequest request) {
super.reset(mapping, request);
}
}




Use of custom action form in struts-config.xml:

<form-bean name="roleForm" type="com.kpe.resourcePlanning.webapp.forms.ActionFormRoles">
<form-property type="java.util.Map" name="roleMap"/>
<form-property type="java.util.Map" name="assignMap"/>
</form-bean>




JSP snippet showing use of map:
    <c:forEach var="headerPeriod" items="${rHeaderPeriods}" varStatus="column">
<td style="text-align: center;">
<c:set var="hash" value="${headerPeriod.year}.${headerPeriod.index}"/>

<c:if test="${column.index lt 2}">
${role.timehash[hash].value}
</c:if>
<c:if test="${column.index gt 1}">
<html:text property="roleMap(${role.id}.${headerPeriod.year}.${headerPeriod.index})" value="${role.timehash[hash].value}" size="3"/>
</c:if>

</td>
</c:forEach>




Struts Action which processes the form:

@SuppressWarnings("unchecked")
public ActionForward saveManageRoles(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
final ApplicationContext ac = this.getAppContext(request);
final ActionFormRoles f = (ActionFormRoles)form;
log.debug("saveManageRoles()");

this.getApplicationController().saveRolesData(ac, (Map)f.get("roleMap"), (Map)f.get("assignMap"));
ac.setHeaderPeriods(this.getApplicationController().generateHeaderPeriods(ac));
return mapping.findForward("manage");
}




Thanks to the following website for providing a converter for my html and xml text: http://www.felgall.com/htmlt47.htm

Monday, January 12, 2009

Prototype and Scriptaculous

These are snippets that I cannot yet remember by heart:


script type="text/javascript"

Event.observe(
window,
'load',
function() {
alert('put code here');
if ( $('notes') ){
// do stuff here
}
}
);

/script

Friday, October 24, 2008

WebApp Debugging Tips and Tricks

This is a potpourri of tips and tricks for debugging web applications. Stuff I have come across and want to archive. Enjoy.

Viewing Browser Source Code
[IE7: x FFn: ?]
Some applications create 'popup' windows whose menu bar has been hidden. To view the source for these windows, simply press Shift+F10 and select the 'View Source' menu item.

Eclipse : Tomcat
  1. I was "converting" an Eclipse "Java application" to an Eclipse "Dynamic Web Project" (see note 1 below) and I kept getting something like 'cannot resolve type struts.[*]' (unfortunately I did not copy it before I solved it). I am not *exactly* sure what was wrong but I finally went to the Tomcat management console and chose to 'reload' the offending application. Voila... it worked thereafter. This project environment was using the Tomcat plugin. Maybe choosing 'Reload Context' from within the IDE might have worked also?
Note 1: The short version of this longer story is to create a new/empty 'Dynamic Web Project'. Then, it will create various Eclipse files within (app)/.settings. Copy these files to your existing application/.settings directory and make a few minor changes within.


Thread dump: kill -3 processid on Unix, Ctrl-Break in a console in Windows

Tuesday, December 18, 2007

JavaScript and Currency

Ok. So I needed something for my first post. Though I am a huge fan and supporter of "pure" Java, a recent assignment had me looking how to validate the format for text entered in a currency field within a web page. So, almost as if my blog title were prophetic, my first post has to do with JavaScript.

As most of us do, I did a quick web search for how to do this. Most of the pages returned had to do with *adding* formatting to an already valid string. i.e. Turning 123456.78 into $123,456.78

As I read the various snippets of JavaScript, I began to formulate my own method for taking a string and converting it to a number. Quickly I decided to try and use Regular Expressions to help me. As I was narrowing down the syntax needed while continuing to hit websites, I found this helpful website which almost mirrored the expression I was working on. [I like the site's format, content, and interactive sections. I recommend you add it to your favorites.]

Here is the function that I came up with:
function parseMoneyDollars(input) {
var moneyxp = /^(\$)?(\d{1,3},?)*(\d{1,3})(\.\d{1,2})?/;
var money = 0;

if ( null == input ) {
} else {
if ( "" == input ) {
} else {
var result = input.match(moneyxp);
if ( result != null ) {
input = result[0].replace(/,/g,"").replace(/\$/g,"");
money = parseFloat(input);
} else {
confirm(input + " was not recognized as a US currency format.");
}
}
}

return money;
}

To my immediate recognition, the only difference between my RegEx and the one on the referenced website are:
  1. My expression is a little bit shorter because it groups by the thousands with the optional comma-delimiter. Some may argue that the following strings should not be recognized, but they are: 987,654321.98 7654,321.98
  2. Because my function converts and returns a number, there is no need to force the first group to the digits 1-9. Any leading zeroes will not "harm" the conversion.
I am currently finishing some testing of the code and regular expression. I will post an update soon. Thanks for visiting and welcome to my blog.

As suspected, my testing revealed several "undesired" results. For my needs, the following version makes the function better. The most significant difference is that it uses a different expression depending on whether the comma delimiter is detected. An important feature (but maybe less important for you) is the strict enforcement of the begin-string and end-string anchors:
function parseMoneyDollars(input) {
var moneyxp = /^(\$)?\d+(\.\d\d?)?$/;
var money = 0;

if ( null == input ) {
} else {
if ( "" == input ) {
} else {
if ( input.search(",") > -1 ) {
moneyxp = /^(\$)?(\d{1,3},)(\d{3},)*(\d{3})(\.\d{1,2})?$/;
}

var result = input.match(moneyxp);
if ( result != null ) {
input = result[0].replace(/,/g,"").replace(/\$/g,"");
money = parseFloat(input);
} else {
confirm(input + " was not recognized as a US currency format.");
}
}
}

return money;
}


Again, feedback is welcome and encouraged (but courtesy is expected even if you disagree with something ;-)

VisualVM on Windows with SDKMAN

 7/31/2024 - I have been using SDKMAN on Windows via Git Bash for some time now and truly like it.  I did however come across an interesting...