Wednesday, October 31, 2007

Generate is property set methods in JAXB objects

Keywords:
JAXB "is property set" method object

Problem:
Defining a default value in the schema does not come through as a default value in the generated objects. This could be worked around if you could check for when a field has been explicitly set in the XML (as opposed the value being returned by the get or is) method being the default).

Solution:
Along the lines of past post - Getting xs:any as DOM object

You simply add another custom binding property:
<xs:appinfo>
    <jaxb:property generateIsSetMethod="true"/>
</xs:appinfo> 

This post has the snippet: How do you pick up default values from XSD/JAXB
Reasonable summary of Customizing JAXB Bindings (though not that easy to read): Customizing JAXB Bindings.

Friday, August 24, 2007

Firefox does not animate my gifs

Keywords:
firefox gif not animated

Problem:
Why is my animated gif working fine in IE but not firefox?

Solution:
The solution was on mozillaZine - I'm fairly sure I haven't turned image animation off explicitly, but to turn it on again:

  1. Type about:config in the address bar

  2. filter for "image.animation_mode"

  3. if you're like me, you'll see this is set to "none". Change this to the default value of "normal".

Thursday, August 16, 2007

Firefox does not reflect input form field values via innerHTML

Keywords:
firefox innerHTML form input field value text select textarea

Problem:
In IE (and therefore the GWT test shell running on windows) you can call innerHTML on a DOM object and where it contains HTTP form input fields you will see an up-to-date reflection of the inputs from the user.

On firefox you simply get a reflection of the DOM as it was originally served up to the user.

This is a problem if you want to move HTML around and not loose the inputs already made by the user.

Eg: On clicking the button in firefox you won't see the input entered in the text box.
<form action="" method="get">       
    <SPAN id="MyContent">           
        <input type="text" name="textField" value="" /><br/>
    </SPAN>
</form>           
  
<button onClick="window.alert(MyContent.innerHTML);">discover user input</button>


Solution:
Found the solution on comp.lang.javascript - Firefox does not reflect selected option via innerHTML. I've extended the example code from this post to handle checkbox, radio and textarea ...

The idea is, every input field on the page must have an onBlur="updateDOM(this)" event handler, forcing the DOM to be updated and reflect the user's input.
<script type="text/javascript">
//
// Will be called by input fields when in 'update DOM' mode. This will
// make sure that changes to input fields in the form will be captured
// in the DOM - not necessary in IE but is required in Moz, etc as the DOM
// will otherwise reflect the page as it was initially.
//
// inputField : the input field that has just been tabbed out of (onBlur) OR the ID of the input field
function updateDOM(inputField) {
    // if the inputField ID string has been passed in, get the inputField object
    if (typeof inputField == "string") {
        inputField = document.getElementById(inputField);
    }
    
    if (inputField.type == "select-one") {
        for (var i=0; i<inputField.options.length; i++) {
            if (i == inputField.selectedIndex) {    
                inputField.options[i].setAttribute("selected","selected");
            } else {
                inputField.options[i].removeAttribute("selected");
            }
        }
    } else if (inputField.type == "select-multiple") {
        for (var i=0; i<inputField.options.length; i++) {
            if (inputField.options[i].selected) {
                inputField.options[i].setAttribute("selected","selected");
            } else {
                inputField.options[i].removeAttribute("selected");
            }
        }
    } else if (inputField.type == "text") {
        inputField.setAttribute("value",inputField.value);
    } else if (inputField.type == "textarea") {
        var text = inputField.value;
        inputField.innerHTML = text;
        inputField.setAttribute("value", text);
    } else if (inputField.type == "checkbox") {
        if (inputField.checked) {
            inputField.setAttribute("checked","checked");
        } else {
            inputField.removeAttribute("checked");
        }
    } else if (inputField.type == "radio") {
        var radioNames = document.getElementsByName(inputField.name);
        for(var i=0; i < radioNames.length; i++) {
            if (radioNames[i].checked) {
                radioNames[i].setAttribute("checked","checked");
            } else {
                radioNames[i].removeAttribute("checked");
            }
        }
    }
}
</script>

<form action="" method="get">        
    <SPAN id="MyContent">            
        <input type="text" name="textField" value="" onBlur="updateDOM(this)"/><br/>
    </SPAN>
</form>            
    
<button onClick="window.alert(MyContent.innerHTML);">discover user input</button>


Notes:
It gets slightly trickier if you have input fields that don't get filled in by the user - eg a date picker dropdown, which will set the textbox with the date for the user, hence they never click in the box and trigger the 'onBlur'. In this case, you'd put the onBlur event on the date picker button

Eg:
<input type="text" name="dateField" id="dateField" value="" onBlur="updateDOM(this)"/>
<button id="myDatePicker" onClick="... do datepicking stuff ..." onBlur="updateDOM('dateField')">
 ... date picking image ...
</button>


Post updated (Thu, 25 Mar 2010): With thanks to the helpful commentors, the above script incorporates better handling for textArea & radio fields as well as an issue I came across for 'select-multiple' (was missing from the original script). It should work fine with the update via document or form approaches discussed in the comments - as opposed to the onBlur which continues to be good enough for my usage.

Post updated (Fri, 5 Apr 2013): Beware trying to set innerHTML text with newlines - IE will lose them. Work around is set the value attribute afterwards and this will honour the newlines (and is meaningless for other browsers).

Friday, July 20, 2007

JAXB xs:any xml content missing from marshalled output

Keywords:
JAXB xs:any xml content missing from marshalled output processContents="lax"

Problem:
I'm defining an XML schema that needs to be able to include any XML - "xs:any" seems perfect for the job. Also need to generate JAXB objects from this schema ... everything seems fine on compilation and in constructing the JAXB objects. The problem is at runtime, it appears that the "any" content is missing from the JAXB objects.

example schema

<xs:schema
    targetNamespace="http://example.com/xml"
    xmlns="http://example.com/xml"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">
    <xs:element name="MyXmlObject">
        <xs:complexType mixed="true">
            <xs:sequence minOccurs="0">
                <xs:any namespace="##any" processContents="lax" minOccurs="0"/>
            </xs:sequence>
            <xs:attribute name="firstName" type="xs:string" use="required"/>
            <xs:attribute name="lastName" type="xs:string" use="required"/>
            <xs:attribute name="happy" type="xs:boolean" use="optional"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

example JAXB object usage

String xmlContent = "<foo>misc. text</foo>";

InputSource source = new InputSource(new StringReader(xmlContent));
Element domElem = (Element)NodeUtils.parseStream(source, true);
myXmlObject.getContent().add(domElem);

JAXBContext jc = JAXBContext.newInstance("com.example.xml");
// marshal to System.out
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( response, System.out);

example XML output (missing my any content)

<MyXmlObject xmlns="http://example.com/xml" firstName="bar" lastName="bar" happy="true">
</MyXmlObject>

Solution:
The JAXB 1.0.x FAQ had the answer - Can I access <xs:any> as a DOM node?. There's detailed notes here with links to example schema and the Bug report, but basically "the spec doesn't support the mapping to DOM, so the RI is not allowed to do this" ... but it will if you put it in "extension mode".

This involves adding some extra elements to your schema and compiling with the "-extension" switch (or extension="true" attribute if using the XJC ant task).

new example schema (with JAXB customisation)

<xs:schema
    targetNamespace="http://example.com/xml"
    xmlns="http://example.com/xml"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    elementFormDefault="qualified"
    attributeFormDefault="unqualified"
    jaxb:extensionBindingPrefixes="xjc"
    jaxb:version="1.0">
    <xs:element name="MyXmlObject">
        <xs:complexType mixed="true">
            <xs:sequence minOccurs="0">
                <xs:any namespace="##any" processContents="lax" minOccurs="0">
                    <xs:annotation>
                        <xs:appinfo>
                            <xjc:dom/>
                        </xs:appinfo>
                    </xs:annotation>
                </xs:any>
            </xs:sequence>
            <xs:attribute name="firstName" type="xs:string" use="required"/>
            <xs:attribute name="lastName" type="xs:string" use="required"/>
            <xs:attribute name="happy" type="xs:boolean" use="optional"/>
        </xs:complexType>
    </xs:element>
</xs:schema>

Wednesday, July 18, 2007

NullPointerException tomcat5 realWriteChars

Keywords:
NullPointerException tomcat5 realWriteChars servlet

Problem:
Getting this stack trace on each access of a servlet:

java.lang.NullPointerException
 at org.apache.coyote.tomcat5.OutputBuffer.realWriteChars(OutputBuffer.java:569)
 at org.apache.tomcat.util.buf.CharChunk.flushBuffer(CharChunk.java:435)
 at org.apache.tomcat.util.buf.CharChunk.append(CharChunk.java:366)
 at org.apache.coyote.tomcat5.OutputBuffer.write(OutputBuffer.java:516)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:149)
 at org.apache.coyote.tomcat5.CoyoteWriter.write(CoyoteWriter.java:158)
 at org.apache.coyote.tomcat5.CoyoteWriter.print(CoyoteWriter.java:208)
 at org.apache.coyote.tomcat5.CoyoteWriter.println(CoyoteWriter.java:265)
 at com.example.MyServlet.doGet(MyServlet.java:56)


The line number in "MyServlet" code that's kicking this off is a simple PrintWriter.println() ... what it's writing to the stream is definitely not null. How could a NPE be caused in tomcat?

Solution:
I wouldn't have guessed at the issue if not trying the same servlet on WebSphere ... then you get a more useful error message:
Invalid character encoding "UTF=8"

There's a typo (ie '=' instead of '-') in the call to set the content type on the HttpResponse object! Correcting this to "UTF-8" fixes the issue:
response.setContentType("text/html; charset=UTF-8");

Thursday, June 28, 2007

IE ignores inline script added to DOM

Keywords:
internet explorer GWT DHTML AJAX inline javascript "Object expected"

Problem:
I've got javascript code (GWT in this case) that adds an inline script to the DOM:
   <input ... onClick="myFunction()"/>
   <script type="text/javascript">
       function myFunction() {
           ... do stuff
       }
   </script>


If this code was on the page from the beginning, the event call to the function works fine. When this HTML is added to the page after it's loaded it appears the function call from the event fails.

IE Error (from the bottom left "! Done" in the status bar):

Line: 1
Char: 1
Error: Object expected


Further frustration - it works fine in Firefox.

Solution:
Aside: I haven't actually worked out why, but in GWT, if you use the method in a FlexTable setHTML the javascript will also not work in Firefox - you need to use setWidget(..).

Internet Explorer will not compile inline javascript code added to the DOM after the page has been loaded. What IE is trying to tell me in its cryptic error message is it's trying to call the function but can't find it.


Notes:
A good example of how to "smuggle" javascript into the DOM via img onLoad - Have Your DOM and Script It Too.

Monday, May 21, 2007

Avoid Copy & Paste with Ant MacroDef

Keywords:
ant java copy paste macrodef gwt compile task

Problem:
There's no convenient ant task to allow you to compile (or re-compile) the GWT client files, but you can get some decent up-to-date check & compile behaviour going with a few lines of ant

... problem is, you need to duplicate these lines of code for every module in the project. It would be nice if you could modularise this.

Solution:
The Ant "macrodef" task lets you define a sequence of ant steps in a parameterised way and then call it any number of times with different parameters.

As can be seen in the example below (which handles 2 modules), adding a new module will require:
  1. add a new entry to the "depends" list for gwt-generate (eg 'gwt-generate-newmod')
  2. create a gwt-compile target 'gwt-generate-newmod' with an "unless" attribute of 'gwtGenerate.newmod.notRequired'
  3. create a gwt-uptodate target to set the property 'gwtGenerate.newmod.notRequired' accordingly.
Yes, there's still some copy and paste, but you're just defining the module name and location rather that repeating the gwt-compile definition so there's less chance for a mistake.
<!-- this is the root target which will do all the generation (if required) -->
<target name="gwt-generate" description="Generate GWT code"
  depends="gwt-generate-common, gwt-generate-demo"/>

<target name="gwt-generate-common" depends="compile, gwt-check" unless="gwtGenerate.common.notRequired">
    <gwt-compile module="com.example.gwt.common.MyCommonModule"/>
</target>
<target name="gwt-generate-demo" depends="compile, gwt-check" unless="gwtGenerate.demo.notRequired">
    <gwt-compile module="com.example.gwt.demo.MyDemoModule"/>
</target>

<!-- this sets the *.notRequired properties if gwt code is uptodate -->
<target name="gwt-check">
  <!-- won't have any effect if the dirs are already there -->
  <mkdir dir="${build.home}/gwt"/>
  <mkdir dir="${build.home}/gwt/tmp"/>
  <mkdir dir="${build.home}/gwt/out"/>

    <gwt-uptodate property="gwtGenerate.common.notRequired"
            module="com.example.gwt.common.MyCommonModule"
            package="src/com/example/gwt/common"/>

    <gwt-uptodate property="gwtGenerate.demo.notRequired"
                    module="com.example.gwt.demo.MyDemoModule"
                    package="src/com/example/gwt/demo"/>          
</target>

<!-- this defines a macro task 'gwt-uptodate' -->
<macrodef name="gwt-uptodate" description="sets a property indicating if the module is up to date">
 <attribute name="property"/>
 <attribute name="module"/>
 <attribute name="package"/>
 <sequential>
         <!-- the module is uptodate if the .nocache.html is not older than any of the module src files -->
      <uptodate property="@{property}"
              targetfile="${build.home}/gwt/out/@{module}/@{module}.nocache.html">
          <srcfiles dir="@{package}" includes="**/*.*"/>
      </uptodate>                      
 </sequential>
</macrodef>  
<!-- this defines a macro task 'gwt-compile' -->
<macrodef name="gwt-compile" description="generates the GWT client code">
 <attribute name="module"/>
 <sequential>
         <!-- you must fork or it will fail -->
         <java dir="${build.home}/gwt/tmp" classname="com.google.gwt.dev.GWTCompiler" fork="true">
          <classpath>
              <!-- src directory containing module definition must be first! -->
              <pathelement location="src"/>
              <pathelement location="${build.home}/classes"/>
              <pathelement location="${gwt.user}"/>
              <pathelement location="${gwt.dev}"/>
              <pathelement location="${gwt.widgets}"/>
            </classpath>
          
          <sysproperty key="java.awt.headless" value="true"/>             
          <arg value="-out"/>
          <arg value="../out"/>
          <arg value="@{module}"/>  
      </java>
 </sequential>
</macrodef>


Notes:
Note, you only need to GWT-compile modules with an EntryPoint class in them. This is because it's only EntryPoint classes that you need to reference from your HTML and on compilation all the classes (and files in com.example.gwt.package/public!) are compiled/copied to this module. This means if you have multiple EntryPoint modules in your project (as I do) that reference a common Module, they will have their own compiled copy of this (and the /public files) rather than referencing it in a common location.

Note also, this means that the gwt-uptodate won't trigger a recompile if there's a change to a referenced module - as it's only checking the source folder containing the EntryPoint module ... so in those cases, you'll need to do a clean of the build folder containing generated source to guarantee everything is compiled up to date.

New Note: the sysproperty to set awt to headless is crucial on linux (if you're using ImageBundles). See Does the GWT 1.4 Compiler Need an X11 Window in Linux?

Monday, May 07, 2007

JavaMail Exception 550 relaying mail is not allowed

Keywords:
JavaMail Exception 550 relaying mail to is not allowed

Problem:
Running server side code that sends an email is being rejected by the SMTP server:

javax.mail.SendFailedException: Invalid Addresses;
  nested exception is:
        com.sun.mail.smtp.SMTPAddressFailedException: 550 relaying mail to example.com is not allowed
        at com.sun.mail.smtp.SMTPTransport.rcptTo(SMTPTransport.java:1196)
        at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:584)
        at javax.mail.Transport.send0(Transport.java:169)
        at javax.mail.Transport.send(Transport.java:98)


Contrary to the error message, its not an issue isolated to the "To" recipient address. No matter what the "To" field was, the relay error was the same with the ???.com substituted in.

Other posts/support-resources on the web point to issues with authentication - but this SMTP server does not require authentication, just that the host is one of a set of IP addresses. Other web applications on the same host, running in the same (tomcat) application server are sending mail to this SMTP server with no problems.

Solution:
In this case, the difference was the spec of the JavaMail libraries. The apps that were working were all using spec 1.2 (deployed with activation.jar, mail.jar and mailapi.jar).

Our app getting the relay error was using spec 1.3 (implementation version 1.4). Downgrading the libraries (ie putting the 3 older jars in WEB-INF/lib) resolved the problem - no more errors from the SMTP server.

There may be a change in spec to do with the way the host is identified. If the libraries were identifying the client code's host as anything other than the IP address then this may be the problem. Perhaps the new libraries require additional properties to configure this behaviour? For the moment things are working but I may get to the bottom of this later ...

Wednesday, March 21, 2007

JSP EL expressions are being ignored by tomcat

Keywords:
tomcat JSP JSTL EL

Problem:
Hopefully this is my last post about the possible problems with JSP/web-app specs and EL. In this case, there's a JSP using EL
Eg:

<%
String myUrl = (String)session.getAttribute("SESSION_KEY_MY_URL");
pageContext.setAttribute("myUrl", returnUrl);
%>
<form name="load" action="${myUrl}" method="GET">


It's coming out in HTML with the EL untouched (but the scriptlet is definitely being run).

<form name="load" action="${myUrl}" method="GET">


Why is the EL being ignored?

Solution:
As with the previous 2 posts on this issue, you have to fix the schema reference in the web.xml (there's too many differing copies of the web.xml(s) I'm dealing with here) and make sure the JSP has the right tablib uri reference - see this post.

For the first time I found this didn't immediately solve the problem! The HTML is coming out the same with EL unevaluated. The issue is that the JSP has been compiled to TOMCAT_HOME\work\Catalina\localhost\MyApp\org\apache\jsp\jsp\myfolder\MyJSP.java and tomcat sees no need to recompile even though I've updated the spec of the webapp.

The solution is to stop tomcat, remove the contents of TOMCAT_HOME\work and restart (OR update the timestamp on the JSP source file(s) to force recompilation). The JSP will be recompiled (to the right spec 2.0 now) and the EL will be evaluated as you expect.

Tuesday, March 20, 2007

How-to turn off tomcat session serialization

Keywords:
tomcat session serialization NotSerializableException "Cannot serialize session attribute" Manager

Problem:
On restarting tomcat there's a stacktrace (below) about an attribute in the session not being serializable. It doesn't seem to effect the application starting up and the application works fine, but these messages at startup are annoying.

2007-03-20 10:50:57,890 INFO [org.apache.catalina.session.ManagerBase@898] - 
java.io.NotSerializableException: com.example.package.MyBeanClassName
        at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1054)
        at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:278)
        at java.util.ArrayList.writeObject(ArrayList.java:531)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


If you want to put (transient) non-serializable objects in the session, how do you stop tomcat from serializing them at shutdown/startup?

Solution:
This was hard to find, but you need to configure a Manager in the context of the application. This should be put in either:
  • the YourApp.war:/META-INF/context.xml

  • the TOMCAT_HOME/conf/Catalina/localhost/YourApp.xml file

  • OR the default context ...

<!-- Turn off session serialization -->
    <Manager className="org.apache.catalina.session.PersistentManager"
      debug="0" distributable="false" saveOnRestart="false">
        <Store className="org.apache.catalina.session.FileStore"/>
    </Manager>


The tomcat documentation for the Manager element will give a bit more information, but it doesn't show the className for the file-store Store element, which is crucial if you're using the PersistentManager class - even if you're configuring it to do nothing!

You'll know it's working when there are no longer any files called "SESSIONS.ser" in the TOMCAT_HOME/work/Catalina/localhost/YourApp folder.

Thursday, March 15, 2007

Can't get or find errorData attribute in JSP pageContext

Keywords:
error JSP pageContext errorData scriplet

Problem:
Writing a JSP that handles errors from JSP, servlets (and other!) need to access the ErrorData object in a scriptlet rather that the convenient JSP EL ${pageContext.errorData}.

Tried:
pageContext.getAttribute("errorData"); but this returns null. Maybe it's not in the page scope.
pageContext.findAttribute("errorData"); but still null.

Solution:
Thankfully there's the convenience method:
pageContext.getErrorData();

This works. It seems the JSP EL ${pageContext.errorData} is a way of referencing this accessor rather than an element in the pageContext "map".

Wednesday, March 14, 2007

Structured data to GWT component with JSON

Keywords:
GWT JSON stuctured initialisation data

Problem:
In a previous post I described using the internationalisation Dictionary class to pass in initialisation data. But what if the data is more complex than key-value pairs? You could define a dictionary value as being a delimited (e.g. space or comma separated) list of tokens but is there an easier way of getting in basic structured data without writing your own parser?

Solution:
JavaScript Object Notation (JSON) is a ".. text-based, human-readable format for representing objects and other data structures" (definition from wikipedia - the article includes a good introduction with examples). GWT supports reading and producing data in this format via the com.google.gwt.json.client package. For data interchange I think your still better off using a GWT remote service and sending your beans to it (let GWT handle the encoding/decoding) but for the host page giving data to the component JSON comes into its own.

Step 1


In the host page, define a dictionary as before but the value (or values) is/are now JSON strings rather than plain strings. In this example I'm creating an array of objects, each object having a property "id" and optionally a property "label" (it's got to be on one line as far as I can tell for the dictionary to allow it):
showHide: "[{\"id\": \"A\", \"label\": \"see A detail?\"}, {\"id\": \"B\", \"label\": \"include B detail?\"}, {\"id\": \"C\"}]"

Step 2


In the GWT component, use the dictionary to get at the JSON string. Then use the JSONParser to convert this to a JSON instance - in this example a JSONArray of JSONObjects. For a JSONObject you can get at each of its properties like you would a map via the get(String key) method.
public void onModuleLoad() {
    Dictionary properties = Dictionary.getDictionary("ModuleProperties");
  
    String showHideConfigString = properties.get("showHide");
    JSONArray showHideConfigs = (JSONArray)JSONParser.parse(showHideConfigString);
    
    List panels = new ArrayList();
    for (int i = 0; i < showHideConfigs.size(); i++) {
        JSONObject config = (JSONObject)showHideConfigs.get(i);
        
        JSONString idValue = (JSONString) config.get("id");
        String id = idValue.stringValue();
        
        JSONString labelValue = (JSONString) config.get("label");
        String label = (labelValue == null)? "include?" : labelValue.stringValue();
        
        // ... now we can do stuff with the data
        ShowHidePanel showHidePanel = new ShowHidePanel(label, id);
        RootPanel.get(id).add(showHidePanel);
        panels.add(showHidePanel);
    }
    
    // ... etc


Notes:
Someone asked me via comments how would you handle request parameters ... it's up to you to make something that can process the request parameters (CGI, java servlet, ASP?) and write a host page containing the data from the request params for the GWT component to then have access to them.

For many this will be obvious, but I felt bad for not including their comment ... but I don't want questions on the blog. Hope that helps.

If the data is more complex/rich than what JSON allows, there's XML.

Wednesday, February 28, 2007

org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported.

Keywords:
Compile JSP tomcat JSTL error functions "org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported"

Problem:
Some fairly standard use of JSTL:
<c:out value="${fn:escapeXml(myvalue)}" />

i.e. using a function in the value field of the c:out tag gives the error:
org.apache.jasper.JasperException:
    <h3>Validation error messages from TagLibraryValidator for c</h3>
    <p>41: tag = 'out' / attribute = 'value': 
        An error occurred while parsing custom action attribute "value" with value "${fn:escapeXml(myvalue)}": 
            org.apache.taglibs.standard.lang.jstl.parser.ParseException: EL functions are not supported.</p>


Solution:
It's the old mismatched spec issue again. Same solution as described in According to TLD or attribute directive in tag file, attribute X does not accept any expressions - namely, fix the schema reference in the web.xml and make sure the JSP has the right tablib uri reference.

Tuesday, January 23, 2007

GWT POST request doesn't include parameters

Keywords:
GWT POST request parameters HTTP HTML RequestBuilder AJAX

Problem:
Following the GWT documentation for making a http-post but it's not clear what the post data should look like if you want it to include form parameters. The newer documentation for com.google.gwt.http.client has a bit more detail but the server side code processing the request (a java servlet) says there's no parameters in the request.

Solution:
It's not in the documentation, but if you want to post form data you must set the "Content-type" header value in the request to "application/x-www-form-urlencoded"

For Example:
StringBuffer postData = new StringBuffer();
// note param pairs are separated by a '&' 
// and each key-value pair is separated by a '='
postData.append(URL.encode("YourParameterName")).append("=").append(URL.encode("YourParameterValue"));
postData.append("&");
postData.append(URL.encode("YourParameterName2")).append("=").append(URL.encode("YourParameterValue2"));

RequestBuilder builder = new RequestBuilder(RequestBuilder.POST, "/yourserver/formprocessor"));
builder.setHeader("Content-type", "application/x-www-form-urlencoded");
try {
  builder.sendRequest(postData.toString(), this /* or other RequestCallback impl*/);
} catch (RequestException e) {
  // handle this
}


Notes:
This sample chapter from the JavaScript™ Phrasebook is useful: Sending a POST Request

Monday, January 15, 2007

How to give initialisation parameters to a GWT component

Keywords:
GWT init initialisation parameter dynamic config

Problem:
Where you have a servlet, JSP or other technology dynamically producing the HTML "host page" for a GWT component, it makes sense that you may want to parameterise the way the GWT component renders/behaves based on certain initialisation/input parameters.

How do pass parameters into the Module?

Solution:
There is a useful Dictionary facility in the Internationalisation (I18N) module ... it doesn't really have anything to do with Internationalisation but it's in this module because you could get the host page to provide key-to-locale-specific-message mappings to save the Module using any hard coded message text in a specific language.

It's generic enough that you could use it for any mapping of values.

The GWT documentation for Dictionary shows how to import the I18N module to your own module and then load the key-value mappings defined in the host page from your GWT code.

Friday, January 05, 2007

GWT shell resource not found *.nocache.html

Keywords:
GWT AJAX shell resource not found nocache.html cache.html

Problem:
Following the Developer guide for making a GWT UI module. The code compiles fine with the GWT compiler and I now what to test and run using the GWT shell.

It starts up fine but I get the following error in the tree log of the shell when it opens up the HTML test page:
The development shell servlet received a request for
'com.example.gwt.mypackage.client.MyEntryPointClass.nocache.html'
in module 'com.example.gwt.mypackage.MyModuleName'

Solution:
My examplisation of the error message highlights what the problem was ...

The HTML "host page" must reference the module name in the meta tag, not the EntryPoint class or the ".client" package (it should be called .client if you want to use the GWT expectations for where things are). The module name is typically the package name parent of the ".client" package plus the name of the *.gwt.xml config file minus the extension.

Eg:
<meta name='gwt:module' content='com.example.gwt.MyModuleName'/>

Thursday, January 04, 2007

JSTL TransformerFactoryImpl ClassCastException on WAS 6.0.2.11

Keywords:
JSTL TransformerFactoryImpl ClassCastException WAS 6.0.2.11 xalan JAXP core xerces

Problem:
A web application that has the following properties:
  1. includes the JAXP api jar files (in WEB-INF\lib)
  2. deploys with the class loader properties of "Parent Last"
  3. uses JSTL core
Will encounter the following stack trace from WAS when ever a JSP is loaded that contains JSTL (core reference):

JSP Processing Error
HTTP Error Code: 500
java.lang.ClassCastException: org.apache.xalan.processor.TransformerFactoryImpl
at javax.xml.transform.TransformerFactory.newInstance(Unknown Source)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl._getInputStream(PageDataImpl.java:125)
at com.ibm.ws.jsp.translator.visitor.validator.PageDataImpl.getInputStream(PageDataImpl.java:117)
at org.apache.taglibs.standard.tlv.JstlBaseTLV.validate(JstlBaseTLV.java:156)
at org.apache.taglibs.standard.tlv.JstlCoreTLV.validate(JstlCoreTLV.java:96)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.validateTagLib(ValidateVisitor.java:939)
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.visitJspRootStart(ValidateVisitor.java:453)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.processJspElement(JspVisitor.java:124)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.visit(JspVisitor.java:110)
at com.ibm.ws.jsp.translator.JspTranslator.processVisitors(JspTranslator.java:121)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJsp(JspTranslatorUtil.java:168)
at com.ibm.ws.jsp.translator.utils.JspTranslatorUtil.translateJspAndCompile(JspTranslatorUtil.java:81)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.translateJsp(JSPExtensionServletWrapper.java:360)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper._checkForTranslation(JSPExtensionServletWrapper.java:329)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.checkForTranslation(JSPExtensionServletWrapper.java:237)
at com.ibm.ws.jsp.webcontainerext.JSPExtensionServletWrapper.handleRequest(JSPExtensionServletWrapper.java:144)
at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:3003)
at com.ibm.ws.webcontainer.webapp.WebGroup.handleRequest(WebGroup.java:221)
at com.ibm.ws.webcontainer.VirtualHost.handleRequest(VirtualHost.java:210)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:1958)
at com.ibm.ws.webcontainer.channel.WCChannelLink.ready(WCChannelLink.java:88)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:472)
at com.ibm.ws.http.channel.inbound.impl.HttpInboundLink.handleNewInformation(HttpInboundLink.java:411)
at com.ibm.ws.http.channel.inbound.impl.HttpICLReadCallback.complete(HttpICLReadCallback.java:101)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.requestComplete(WorkQueueManager.java:566)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.attemptIO(WorkQueueManager.java:619)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager.workerRun(WorkQueueManager.java:952)
at com.ibm.ws.tcp.channel.impl.WorkQueueManager$Worker.run(WorkQueueManager.java:1039)
at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java:1470)


Solution:
In short, make sure the JSPs, JSTL refs and the web app are 2.4 compliant (see past post: What Spec?) and install the latest fix pack for WAS from IBM.

In detail, the following Problem ID is a different issue but underlying problem is the same - incorrect handling of loading XML & XSLT API classes for Parent Last apps - IBM - PK26233. The comment says it is resolved in the fix pack 6.0.2.15 for WebSphere Application Server, but I used 6.0.2.17 seeing it was newer - V6.0.2 Fix Pack 17.