Monday, August 20, 2007

Latitude Longitude hover values on a map mashup

This is just a simple little latitude & longitude map mashup to compile rough data points for testing


Instructions: Click on the map to record a point and get the lat/lng of your desired position

(you can record ten clicks before requiring a page refresh)



Saturday, July 14, 2007

Asset Packager with Custom Rhino for super optimized JavaScript

Scott Becker has a wicked Javascript/CSS rails gem documented at:
http://synthesis.sbecker.net/pages/asset_packager

If like me, you have a stray missing semi-colon somewhere or would prefer to have the compression done in a compiled way as opposed to jsmin's regular expression substitution,

(note this requires a java runtime)

1. download DOJO shrinksafe's Custom Rhino jar from here into /vendor/plugins/asset_packager/lib

2. and then modify
/vendor/plugins/asset_packager/lib/synthesis/asset_package.rb as follows:
def compress_js(source)
#jsmin_path = "#{RAILS_ROOT}/vendor/plugins/asset_packager/lib"
custom_rhino_path = "#{RAILS_ROOT}/vendor/plugins/asset_packager/lib"
tmp_path = "#{RAILS_ROOT}/tmp/#{@target}_#{revision}"

# write out to a temp file
File.open("#{tmp_path}_uncompressed.js", "w") {|f| f.write(source) }

# compress file with JSMin library
#`ruby #{jsmin_path}/jsmin.rb <#{tmp_path}_uncompressed.js >#{tmp_path}_compressed.js \n`

cmd = "java -jar #{custom_rhino_path}/custom_rhino.jar -c #{tmp_path}_uncompressed.js > #{tmp_path}_compressed.js \n"
`#{cmd}`
...

PS. I havent yet chased up an easy way to rebuild the custom_rhino.jar with dojo's diff for newline stripping etc.

Saturday, May 26, 2007

Configuring HTTP Timeout for Rails GeoKit::Geocoders Plugin

Problem Description:
My internet connection is pretty spotty and when it drops out, the
IpGeocoder.geocode(request_ip)
functionality from the GeoKit::Geocoders Plugin takes forever and a day to resolve.

Problem Solution:
I directly hacked
vendor/plugins/geokit/lib/geo_kit/geocoders.rb
as follows:

class IpGeocoder < Geocoder

private

# Given an IP address, returns a GeoLoc instance which contains latitude,
# longitude, city, and country code. Sets the success attribute to false if the ip
# parameter does not match an ip address.
def self.do_geocode(ip)
return GeoLoc.new unless /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})?$/.match(ip)
# response = Net::HTTP.get_response('api.hostip.info', "/get_html.php?ip=#{ip}&position=true")

domain = 'api.hostip.info'
path = '/get_html.php'
pars = "ip=#{ip}&position=true"
h = Net::HTTP::new(domain)
h.read_timeout = 2
begin
response = h.post(path, pars)
rescue TimeoutError => e
raise "Error calling #{domain}, #{path}, #{pars}: #{e.inspect}"
end

response.is_a?(Net::HTTPSuccess) ? parse_body(response.body) : GeoLoc.new
rescue
logger.error "Caught an error during HostIp geocoding call: "+$!
return GeoLoc.new
end

Tuesday, February 06, 2007

Email Form Validation in Ruby on Rails Tutorial

This tutorial shows how to perform email form validation in Ruby on Rails using the built-in ActiveRecord::Validations framework with a non-persistent model.

Note: This tutorial assumes you already have Rails installed and have successfully created & configured a database for your environment.

Create a new Rails Project from the command line:
C:\temp> rails EmailFormValidation

Note: in order to leverage ActiveRecord validation, the application will need to be hooked into a database, so even though this example doesn’t talk to a database, one needs to be configured anyway:
Modify c:\temp\EmailFormValidation\config\database.yml to point to a locally running database:
development:
adapter: mysql
database: depot_development
username: root
password: password
host: localhost

Install the BaseWithoutTable plugin so that we can validate the model without persistence:
C:\temp> cd EmailFormValidation
C:\temp\EmailFormValidation> ruby script/plugin install http://svn.viney.net.nz/things/rails/plugins/active_record_base_without_table/


Create c:\temp\EmailFormValidation\app\models\Contact.rb to use BaseWithoutTable and set up the email fields:
class Contact < ActiveRecord::BaseWithoutTable
column :name, :string
column :email_address, :string
column :enquiry, :string

validates_presence_of :name
validates_format_of :email_address, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
validates_length_of :email_address, :within => 5..255

def send_email
if save
begin
return true #This tutorial does not cover Email configuration & sending
#return true if ApplicationMailer.deliver( ApplicationMailer.create_contact( self ) )
rescue Object => e

errors.add("There is a problem with our email system and this form could not be submitted")
end
end
false
end

end
Test the Model – the Contact Object should now have validation on save:
(note: If you have not correctly configured a database, you will see an error at this step along the lines of: Mysql::Error: Access denied for user: 'root@localhost')
C:\temp\EmailFormValidation> ruby script/console
>> c = Contact.new
=> #<Contact:0x487171c @new_record=true, @attributes={"name"=>nil, "enquiry"=>nil, "email_address"=>nil}>
> c.save
=> false
>> c
=> #<Contact:0x4823030 @errors=#<ActiveRecord::Errors:0x48217bc @base=#<Contact:

0x4823030 ...>, @errors={"name"=>["can't be blank"], "email_address"=>["is too short (minimum is 5 characters)", "is invalid"]}>, @new_record=true, @attributes=
{"city"=>nil, "company"=>nil, "name"=>nil, "enquiry"=>nil, "number_members"=>nil
, "state"=>nil, "email_address"=>nil}>
>> exit


Create c:\temp\EmailFormValidation\app\controllers\contact_controller.rb:
class ContactController < ApplicationController

def index
if request.post?
@contact_us_email = Contact.new(@params[:contact_us_email])

if @contact_us_email.send_email
flash[:notice] = 'Thank you for the email! We will get back to you ASAP =]'
@contact_us_email = nil
end
end
end

end
Create c:\temp\EmailFormValidation\app\views\contact\ (directory)
Create c:\temp\EmailFormValidation\app\views\contact\index.rhtml:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Contact Us</title>
<style type="text/css">
body{font-family:verdana;}
#contact_us_email label {position:absolute; text-align:right; width:250px;}
#contact_us_email input, #contact_us_email select, #contact_us_email textarea {margin-left:255px; margin-bottom:10px; width:180px;}
#contact_us_email select{width:50px;}
#contact_us_email label.required {text-align:left; font-style:italic; color:#B2B8CC;}
.fieldWithErrors {padding: 2px; background-color: red; display: table;}
#errorExplanation { width: 400px; border: 2px solid red; padding: 7px; padding-bottom: 12px; margin-bottom: 20px; background-color: #f0f0f0;}
#errorExplanation h2 { text-align: left; font-weight: bold; padding: 5px 5px 5px 15px; font-size: 12px; margin: -7px; background-color: #c00; color: #fff;}
#errorExplanation p { color: #333; margin-bottom: 0; padding: 5px;}
#errorExplanation ul li { font-size: 12px; list-style: square;}
#notice {color: green}
</style>
</head>
<body>
<p id="notice"><%= flash[:notice] %></p>
<%= start_form_tag %>
<%= error_messages_for 'contact_us_email' %>
<fieldset id="contact_us_email">
<legend>Contact Us </legend>
<label for="contact_us_email_name">Your Name:</label> <%= text_field(:contact_us_email, 'name', :size => 255) %> <label class="required">(required)</label><br/>
<label for="contact_us_email_email_address">Email Address:</label> <%= text_field(:contact_us_email, 'email_address', :size => 255) %> <label class="required">(required)</label><br/>
<label for="contact_us_email_enquiry">Comments or Questions?</label> <%= text_area(:contact_us_email, 'enquiry', :rows => 6) %><br/>
<label> </label> <%= submit_tag("Submit Enquiry") %>
</fieldset>
<%= end_form_tag %>
</body>
</html>
Launch the built-in Webrick server & test the form:
C:\temp\EmailFormValidation> ruby script/server
Point your web browser to http://localhost:3000/contact

And Bob’s your uncle - The email form should now validate existence of data in the name & email fields and also validate the format of the email address using standard rails form validation.

Enjoy!

This example application can be downloaded from: EmailFormValidation_RoR_Example.zip (77kb)

Labels: , , , , , , , ,

Thursday, January 11, 2007

New Blogger Layouts Feature not compatible with FTP publishing

Background:
We needed a new blog publishing account at work for our Ruby on Rails Blog

We chose Google Blogger which in the past (whilst in Beta) has worked superbly for me.

Problem:
Customizing the layout in the new post-beta Blogger has a whole new tag library (eg. stuff like b:skin, b:section, b:widget etc. etc. instead of the old beta style: $BlogPageTitle$, $BlogMetaData$, $BlogItemTitle$ etc.)

Unfortunately, any layouts developed using this new tag library will not work if you want to use FTP/SFTP publishing because the Blogger application does not support these Templating layout tags for FTP/SFTP (Yet?).

This turned out to be a big waste of time in my case as we had a test blog set up to publish to blogspot which I used for template development (using the new templating tags) and when I tried to copy that template HTML over to our 'real' (Self-hosted, FTP-published) blog, the template tags failed to render.

Layout vs Template Blogger Blog Settings

Solution:
If you have set up the blog as hosted on blogspot.com and want to convert it to FTP publishing, you need to:
- Go to Template Tab > Edit HTML Screen
- Click the 'Revert to Classic Template' link
- Go to Settings Tab > Publishing Screen
- Click on the 'FTP' or 'SFTP' link and configure accordingly

Other Web Resources dealing with this Issue:
How can I use the new Blogger Layouts features?
http://help.blogger.com/bin/answer.py?answer=44474&useful=0&show_useful=1

Blogger Beta: Classic or Beta template?
http://blogger-tricks.blogspot.com/2006/12/blogger-beta-classic-or-beta-template.html

Thursday, December 07, 2006

Mac Widget for Local Search

Funky-looking Local Search Mac WidgetToday I came across Mac Widgets for the first time after using this cool Local Search Widget from Insider Pages.

It was a cool experience (being able to search for businesses eg. My local Taco Bell in a widget without having to launch a web-browser).

I really like how easy it is to make these things (Mac Widgets) - they seem to be made up of some structured DHTML and that's about it!

Note to self: Macs are getting cooler every day (especially amongst developers) - I will have to give it a go as a development environment sometime soon! (Maybe when Internet Explorer becomes standards compliant and web GUI's can be tested solely from Firefox).

Monday, December 04, 2006

Ruby on Rails / PHP HTTP Referer header

Background:
I've noticed Google does a nice job of highlighting your keywords on Googles cached 'HTML' version of indexed PDF documents eg. tutorial pdf

This could performed by checking the Referer HTTP Header
eg.
<%= @request.env["HTTP_REFERER"] %> in Ruby on Rails
$_SERVER["HTTP_REFERER"] in PHP

Problem Description:
I want to get a handle on any Google search query that a user has performed to visit a page on my site so that I can customize content specifically to their interest

eg.
A user searches on 'streetball blog' on Google
eg. http://www.google.com/search?q=streetball+blog
They click on "Jason's Streetball Blog" - a page I administer
I want to customize this page based on their referring keywords.

PHP/Ruby on Rails Problem Solution (ie. getting a handle on referring keywords):
PHP:
$ref = $_SERVER["HTTP_REFERER"]
if (strstr($ref, "google.com/search?")) {
$search_query = "";
$query_arg = strtok($ref, "&");
while ($query_arg !== false) {
if (strstr($query_arg, "q=")) {
$search_query = substr($query_arg, 2);
break;
}
$query_arg = strtok("&");
}
echo $search_query;
}


Ruby on Rails:
# Creates @referring_search containing any referring search engine query minus stop words
#
# eg. If the HTTP_REFERER header indicates page referer as:
# http://www.google.com/search?q=Most+Calories+iN+a+Cheesesteak+at+Belmont&start=0&amp;amp;amp;amp;amp;amp;amp;amp;ie=utf-8&oe=utf-8&client=firefox-a&rls=org.mozilla:en-US:official
#
# then this function will create:
# @referring_search = "Most Calories Cheesesteak Belmont"
#
def setup_referring_keywords
# Check whether referring URL was a search engine result
referer = @request.env["HTTP_REFERER"]
unless referer.nil_or_empty?
search_referers = [
['^http://(www)?\\.?google.*', 'q'],
['^http://search\\.yahoo.*', 'p'],
['^http://search\\.msn.*', 'q'],
['^http://search\\.aol.*', 'userQuery'],
['^http://(www\\.)?altavista.*', 'q'],
['^http://(www\\.)?feedster.*', 'q'],
['^http://search\\.lycos.*', 'query'],
['^http://(www\\.)?alltheweb.*', 'q']
]
search_referers.each do |search_engine|
# Check if the referrer is a search engine we are targetting
pattern = search_engine[0]
reg = Regexp.new(pattern)
if (reg.match(referer))

# Create a globally scoped variable (@referring_search) containing the referring Search Engine Query
query_args = URI.split(referer)[7]
unless query_args.nil_or_empty?
query_param_name = search_engine[1]
query_args.split("&").each do |arg|
if arg.split("=")[0] == query_param_name
unstopped_keywords = CGI.unescape(arg.split("=")[1])
stop_words = Regexp.new(/\b(\d+|\w|about|after|also|an|and|are|as|at|be|because|before|between|but|by|can|com|de|do|en|for|from|has|how|however|htm|html|if|i|in|into|is|it|la|no|of|on|or|other|out|since|site|such|than|that|the|there|these|this|those|to|under|upon|vs|was|what|when|where|whether|which|who|will|with|within|without|www|you|your)\b/i)
@referring_search = unstopped_keywords.gsub(stop_words, '').squeeze(' ')
$logger.info("Referring Search Keywords: #{@referring_search}")
break
end
end
end

break
end
end
end
end

Tuesday, November 21, 2006

<iframe> with 100% Height supporting window resizes, IE & Firefox

Background:
Need to create a resizeable html <iframe> element that stretches to almost the full height of a window.

Expected:
<iframe width="100%" height="100%"></iframe>
to work.

Problem Description:
Setting the iframe.style.width=100% CSS property was incorrectly using the full height of the window and didn't factor the resize event.

Problem Solution:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title>Untitled</title>
<style type="text/css">
body, h1 {margin:0px; text-align:center; color:#000;}
#header_div {background-color:red;}
#diagnosed_site {width:99%; height:100%;}
* html #diagnosed_site {width:100%;} /* IE workaround - firefox needs a 99% width to avoid a horizontal scroll-bar */
</style>
<script>
function resize_iframe() {
var body_height = document.body.clientHeight;
var header_height = document.getElementById("header_div").offsetHeight;
var iframe = document.getElementById("diagnosed_site");
iframe.style.height = parseInt(body_height) - parseInt(header_height) - 5;
}
</script>

</head>

<body onload="resize_iframe()" onresize="resize_iframe()">

<div id="header_div">
<h1>Iframe Test</h1>
</div>

<iframe src="http://www.kangarooit.com/" id="diagnosed_site"></iframe>

</body>
</html>

Monday, November 20, 2006

Sybase Error JZ00L when trying to connect/login to database

Background:
Trying to Connect to a Sybase Database, the login fails with an error message:
An error occured while establishing the connection.
Type: java.sql.SQLException Error Code: 0 SQL State: JZ00L
Message:
JZ00L: Login failed. Examine the SQLWarnings chained to this exception for the reason(s).


Problem Description:
According to the Sybase SQL Error Code description page, error JZ00L occurs as follows:
This error occurs if you enter an incorrect password and/or login ID in the Password and Login ID fields of the Database Profile.

Refer: http://www.sybase.com/detail?id=47902

Problem Solution:
There was no problem with username/password I was using.

The problem I experienced was that the Sybase server had too many idle connections lying around (probably because our network dropped out prior to previous connections disconnecting correctly and we had finally reached our pool limit).

I restarted the Sybase server & it resolved the issue. (It would have been cleaner to kill the idle connections)

Tuesday, August 15, 2006

uninitialized constant FPDF - Ruby on Rails View Page Code

Background:
Trying to use my first Rails plugin - Rfpdf and after following the instructions on the RoR Rfpdf documentation page, my page fails to load. Checking the associated forum didn't help - it's probably something easy because it's the first thing I've ever done anything with Rails.

Problem Description:
when trying:
pdf = FPDF.new()

the following error message is occuring:
uninitialized constant FPDF

I think the problem is that I attempted to install Rfpdf using:
ruby script/plugin install svn://rubyforge.org//var/svn/rfpdf

however it appears that that particular command line syntax is Subversion specific and I did not yet have Subversion installed.

Problem Solution:
Kind of straight-forward and ugly but I downloaded the source from:
http://rubyforge.org/projects/rfpdf/

and copied it into my vendor/profiles directory in my rails application source. I could have downloaded Subversion and done it properly, but apparently we don't use that here at my workplace.

Wednesday, March 22, 2006

Connecting a PDA to a USB Laptop HDD for extra storage


Background:
I recently purchased a HP iPAQ hx 2490 Pocket PC (PDA with Windows Mobile 5.0 Operating System) to take overseas for internet access & entertainment (see figure 1).

Problem Description:
I want to take a lot of entertainment data overseas (movies & mp3's etc.) and also use the device to back up a lot of high resolution photo's that we will be taking.

The PDA could do this either with SD Cards or CF cards, however these mediums are highly expensive storage mediums eg:
$109 AUD - 1gb Sandisk Ultra II Compact Flash Card (from Organiser World)
$109 AUD - 1gb Sandisk Ultra II Secure Digital Card (from Organiser World)


compared to normal Hard Drives eg:
$145 AUD - 80gb Samsung 2.5 inch'' Inch ATA Notebook HDD Hard Disk (from msy)


Ideally, I would like to be able to plug the PDA directly into a laptop HDD Hard Disk using a USB laptop HDD case (eg. refer figure 2.), however when I connect the devices in this fashion (regardless of whether I am using the HP charger adapter to power the cradle), the USB laptop HDD light does not come on to indicate that it is being powered by the PDA.

This indicates to me that there is a master-slave type relationship between USB devices, and that the HP iPAQ 2490 is not capable of performing the 'master' role.

I wonder whether this is a software/Operating System issue with Windows Mobile 5.0 (ie. whether it is/is not permitted by the Operating System)? If so, then I wonder if anyone has written PDA software that will facilitate this connection?

Problem Solution:
The Ratoc USB 1.1 Host Adapter CF Card (CFU1U) (see figure 3) looks like it will solve the problem (of connecting the iPaq PDA to the USB laptop HDD Hard Disk), however at $139 (US), the cost is more then I would like to pay (especially if it would be technically possible to write software that would make the situation in figure 2 work).

Also, I have not come across the Ratoc card here in Australia so have been unable to confirm whether it will work as hoped for with a USB laptop HDD Hard Disk. The question is whether the Windows Mobile 5.0 Operating System will pick up the USB HDD and allow it to be used for transfer of data.

Monday, February 27, 2006

xtags v1.0 parse custom JSP tag using Dom4J Document object parameter

Background:
Trying to parse a Dom4J XML Document using <xtags:parse> in order to iterate through it (XSLT style) inside JSP code.

Problem Description:
The JSP code has an inline Dom4J Document object, however it cannot be passed as a parameter to xtags:parse
eg. when trying:
<%
org.dom4j.Document xmlDoc = ...;
%>
<xtags:parse reader="<%= xmlDoc %>" />

the following error message is occuring:
Explicit cast needed to convert org.dom4j.Document to java.io.Reader._jspx_th_xtags_parse_0.setReader( xmlDoc);

according to the xtags:parse v1.0 API documentation, this is occuring because the reader parameter of xtags:parse requires an object of type java.io.Reader so the question is how to get a java.io.Reader from an org.dom4j.Document (The xtags:parse v1.0 documentation shows how to parse a URL, an XML file, a java.io.Reader etc, but doesn't have an example for an org.dom4j.Document parameter).

Problem Solution:
Kind of straight-forward and ugly but:
<%
org.dom4j.Document xmlDoc = ...;
%>
<xtags:parse>
<%= xmlDoc.asXML() %>
</xtags:parse>
It would have been nicer to have a parameter to the tag that accepts an org.dom4j.Document however the performance doesn't seem to be an issue (ie. with the writing of the XML straight to the output stream).

Monday, February 20, 2006

Dom4j SAXParseException performing XSLT with JSTL 1.0 transform tag

Background:
Trying to perform an XSL Transformation of a Dom4J Document in some JSP. Receiving SAXParseException.

Problem Description:
The Following Code:
Document searchResults = ...

<c:import url="/servlet/test.xsl" var="stylesheet" />

<x:transform xml="${
searchResults}" xslt="${stylesheet}">
<x:param name="currentUrlNoQueryString" value="<%=request.getRequestURI()%>"/>
<x:param name="queryStringNoSortType" value="<%=queryStringNoSortType%>"/>
<x:param name="selectedSortType" value='<%=request.getParameter("selectedSortType")%>'/>
</x:transform>

is producing:
javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: Document root element is missing.


Problem Solution:
The solution was that my path to the XSL file (ie. "/servlet/test.xsl") was not being resolved properly.

ie. I changed it explicitly to:
<c:import url="http://servername/servlet/test.xsl" var="stylesheet" />

and it worked. I Guess the error message wasn't intuitive enough for me at first (a lot of other forum posts eg. this one and this one seem to suggest the same error message can also be caused by invalid ie. non UTF characters at the beginning of the XML file).

As a side-note, I was unable to find a JSTL 1.0 API specification anywhere. The JSTL 1.1 API Specification for the x:transform tag deprecates the xml attribute and the 1.0 specification doesn't yet support the doc attribute.

Thursday, February 16, 2006

Image Thumbnail (16*16px) Icons for common file types

Seems like I am constantly having to find icons for common file types. This page will serve as a reference to find them when needed:

Text (.txt) MimeType: text/plain

WinZip (.zip) MimeType: application/zip

Adobe (.pdf) MimeType: application/pdf

Macromedia Flash SWF (.swf) MimeType: application/zip

Microsoft Word (.doc) MimeType: application/msword

Excel (.xls) MimeType: application/excel

Microsoft Visio (.vsd) MimeType: application/x-visio

Microsoft PowerPoint (.ppt) MimeType: application/powerpoint

GIF Image (.gif) MimeType: image/gif

JPEG Image (.jpg, .jpeg) MimeType: image/jpeg

MPEG Video (.mpeg) MimeType: video/mpeg

BMP Image (.bmp) MimeType: image/bmp

PNG Image (.png) MimeType: image/png

Executable (.exe) MimeType: application/octet-stream

Tuesday, February 07, 2006

Printing server-side JSP scriptlet code to output HTML conditionally from a custom JSP tag

Background:
The Java Web Application (WAR) that I am developing uses a content management system (Fatwire CMS) that executes all JSP code during the publish process and spits the resultant HTML out into static files in the published output WAR.

Problem Description
I needed to be able to conditionally either execute JSP code or write the JSP to the output.

Problem Solution:
The JSP bodycontent attribute of the tag config in the web.xml can be set to either 'JSP' or 'tagdependent' (as per this article) ie:

<bodycontent>tagdependent</bodycontent>


When bodycontent is set to 'JSP' in the web.xml, the following JSP code:
<%= "a" + "b" %>

outputs to the result stream:
ab

Wraps any 'dynamic' server side processing JSP code that is to
be deployed to the application server without being parsed by
the Fatwire publication process.

Also, allows evaluation of the code in preview mode of Fatwire.

however, when bodycontent is set to 'tagdependent' in the web.xml, the same JSP code outputs:
<%= "a" + "b" %>

The question now is how to conditionally determine whether to set bodycontent to 'JSP' or 'tagdependent'

Resolution: Was unable to find a JSP API call that dynamically modified the bodycontent property of the custom tag. As a work-around, implemented a custom version of the Fatwire tag render:sattelitepage (containing if/else logic that either parsed the page in preview mode using ics.ReadPage() or otherwise printed out the include contents if in publish mode)

Note: bodycontent should be set to 'tagdependent' not 'tagdependant' (that typo in the web.xml caused this error for me: jasper.error.bad.bodycontent.type)
Using a custom JSP tag, the conditional
saaj.jar fr

Monday, January 30, 2006

Java Apache Axis upgrade from version 1.1 to 1.2 - IncompatibleClassChangeError

Background:
The Java Web Application (WAR) that I developed makes a Web Service Call. I originally developed the application using Apache Axis version 1.1, however due to server deployment requirements, I have been forced to upgrade to Axis version 1.2.

Problem Description
After changing to the axis.jar in my WEB-INF/lib to Axis 1.2 (from Axis 1.1), the application started throwing the following error:
java.lang.IncompatibleClassChangeError
at org.apache.axis.message.MessageElement.addTextNode(MessageElement.java:1387)
at org.apache.axis.message.SOAPHandler.addTextNode(SOAPHandler.java:148)
at org.apache.axis.message.SOAPHandler.endElement(SOAPHandler.java:112)
at org.apache.axis.encoding.DeserializationContext.endElement(DeserializationContext.java:1087)
at org.apache.xerces.parsers.AbstractSAXParser.endElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanEndElement(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at javax.xml.parsers.SAXParser.parse(Unknown Source)
at org.apache.axis.encoding.DeserializationContext.parse(DeserializationContext.java:227)
at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:696)
at org.apache.axis.Message.getSOAPEnvelope(Message.java:424)
at org.apache.axis.handlers.soap.MustUnderstandChecker.invoke(MustUnderstandChecker.java:62)
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:206)
at org.apache.axis.client.Call.invokeEngine(Call.java:2765)
at org.apache.axis.client.Call.invoke(Call.java:2748)
at org.apache.axis.client.Call.invoke(Call.java:2424)
at org.apache.axis.client.Call.invoke(Call.java:2347)
at org.apache.axis.client.Call.invoke(Call.java:1804)
at au.com.sensis.intranet.webservices.OutlookCalendarSoap_BindingStub.getAllMeetingRequestResponses(OutlookCalendarSoap_BindingStub.java:360)

after finding this forum post, and this post, I tried upgrading the Saaj.jar & jaxrpc.jar.


Problem Solution:
After downloading the Axis release 1.2.1, I upgraded:
saaj.jar from version 1.1 to version 1.1
jaxrpc.jar from version 1.1 to version 1.2

and added:
wsdl4j-1.5.1.jar to WEB-INF/lib

This resolved the IncompatibleClassChangeError. It's a pity Apache didn't implement Axis 1.2 to be backwards compatible with Axis version 1.1.

As a side comment, the Axis upgrade to version 1.2 was good because version 1.1 uses the 'enum' java reserved keyword in it's variable naming which causes warnings when running Java Source code level 1.5.

Note: I was using the mySpotter WSDL2Java Eclipse pluginto generate my Java stub to the web service using the WSDL, however upon examining the manifest.mf of the Axis jar in the com.myspotter.wsdl2java_1.1.0 plugin directory, discovered it was using Axis 1.1. Updating this jar alone didn't work, so I decided (based upon: ) to create an ANT script to generate the Web Service stubs (using wsdl4j-1.4.1.jar from the axis release):

build.properties:

# project information
project.owner =
My Company
project.owner.url = http://mywebservice.asmx
project.fullname =
My Company Web Service Java Client library Jar
project.vendor = My Company
project.name = myproject
project.version = 2
project.year = 2006
build.version = 1

# directory paths
build.dir = c:/temp/jarsbuild
lib.dir = ../../WebApp/WEB-INF/lib
build.dest.dir = ../../Builds
source.dir = ../../src
whos.who.web.service.wsdl.dev = http://x.asmx?WSDL
whos.who.web.service.wsdl.stg = http://x.asmx?WSDL
whos.who.web.service.wsdl.prd = http://x.asmx?WSDL


build.xml
<project name="OutlookUtilsJar" default="init" basedir=".">
<description>Sensis OutlookUtils Jar build file</description>

<property file="build.properties" />

<property name="fetched.dir" location="${build.dir}/fetched"/>
<property name="generated.dir" location="${build.dir}/generated"/>
<property name="pkg.jar.name" value="${project.name}-${project.version}.0.${build.version}"/>
<property name="compiled.src.dir" location="${build.dir}/compiled-src"/>

<target name="init">
<delete dir="${fetched.dir}"/>
<delete dir="${generated.dir}"/>
<mkdir dir="${fetched.dir}"/>
<mkdir dir="${generated.dir}"/>

<antcall target="buildStubJar">
<param name="build.type" value="dev"/>
<param name="wsdl" value="${whos.who.web.service.wsdl.dev}"/>
</antcall>
<antcall target="buildStubJar">
<param name="build.type" value="stg"/>
<param name="wsdl" value="${whos.who.web.service.wsdl.stg}"/>
</antcall>
<antcall target="buildStubJar">
<param name="build.type" value="prd"/>
<param name="wsdl" value="${whos.who.web.service.wsdl.prd}"/>
</antcall>
</target>

<target name="buildStubJar">
<property name="current.jar.name" value="${pkg.jar.name}-${build.type}"/>
<property name="current.src.dir" location="${generated.dir}/${current.jar.name}"/>
<property name="current.classes.dir" location="${current.src.dir}-classes"/>
<antcall target="fetch-wsdl">
<param name="jar.name" value="${current.jar.name}"/>
<param name="wsdl" value="${wsdl}"/>
</antcall>
<antcall target="import-wsdl">
<param name="jar.name" value="${current.jar.name}"/>
<param name="java.src.dir" value="${current.src.dir}"/>
</antcall>
<antcall target="compile-wsdl">
<param name="jar.name" value="${current.jar.name}"/>
<param name="java.src.dir" value="${current.src.dir}"/>
<param name="java.output.dir" location="${current.classes.dir}"/>
</antcall>

<tstamp/>
<jar destfile="${current.src.dir}.jar">
<fileset dir="${current.classes.dir}" />
<manifest>
<attribute name="Manifest-Version" value="${current.jar.name}"/>
<attribute name="Built-By" value="${user.name}"/>
<section name="${project.name}">
<attribute name="Specification-Vendor" value="${project.vendor}"/>
<attribute name="Implementation-Version" value="${TODAY}"/>
</section>
</manifest>
</jar>
<copy file="${current.src.dir}.jar" tofile="${build.dest.dir}/${pkg.jar.name}/${current.jar.name}.jar"/>
</target>

<target name="compile-wsdl">
<mkdir dir="${java.output.dir}"/>
<javac srcdir="${java.src.dir}"
destdir="${java.output.dir}"
classpathref="axis.classpath"
debug="on"
source="1.4"
/>
</target>

<path id="axis.classpath">
<fileset dir="${lib.dir}">
<include name="**/*.jar"/>
</fileset>
</path>

<target name="fetch-wsdl">
<get src="${wsdl}" dest="${fetched.dir}/${jar.name}.wsdl"/>
</target>

<target name="import-wsdl">
<java classname="org.apache.axis.wsdl.WSDL2Java" fork="true" failonerror="true" classpathref="axis.classpath">
<arg file="${fetched.dir}/${jar.name}.wsdl"/>
<arg value="--output"/>
<arg file="${java.src.dir}"/>
<arg value="--verbose"/>
<arg value="--package"/>
<arg value="au.com.sensis.intranet.webservices"/>
</java>
</target>


</project>