Wednesday, March 25, 2009

Submitting Iphone Application to iTunes

Well this proved to be a little bit complicated but it shouldn't be if you carefully follow at least one time all the steps from IPhone developer Program ("Distribution|Prepare App" has all necessary instructions). Anyway here are some important and very basic steps to follow.

1. In XCode navigate to Products/${appname}.app. CTRL + click on top of it and select " Reveal in Finder"
2. In the Finder Window use CTRL + click on top of ${appname}.app and select "compress"
3. Open App Loader and select Menu | File | New and choose your application
4. Follow steps and point to the binary (zip created above)
5. Press Send.



The major problem I got was "application failed codesign verification" after trying to send the binary from App Loader.

Just be sure you follow careful all steps from IPhone developer Program ("Distribution|Prepare App" has them all). The error is very generic and anything you miss will stop your app from being sent to Apple. In my case I was working with the 'Project Info Window' (Menu | Project | Edit Project Settings) all the time, ignoring that many of the steps involve using the 'Target Info Window' (Menu | Project | Edit Active Target)

As a side note the application I was working on had a lot of local resources and being almost 40MB it took 15 minutes to get uploaded. It was not my Internet Connection for sure but just an Apple throughput limitation.

JQuery Tooltip for Html Select Boxes

Sometimes there is limited content width for options showing up in an HTML Select tag. Consider using in those cases JQuery Tooltip plugin:

<!-- Include jquery and tooltip plugin -->
<script src="jquery-1.2.6.js" type="text/javascript"></script>
<script src="jquery.tooltip.js" type="text/javascript"></script>

<!-- Forcing a narrow select box -->
<style type="text/css">
select{
width: 60;
}
option{
width: 60;
}
</style>

<!-- Include custom code to handle the tooltip -->
<script type="text/javascript">
//After loading the page insert the title attribute.
$(function(){
$("select option").attr( "title", "" );
$("select option").each(function(i){
this.title = this.text;
})
});

//Attach a tooltip to select elements
$("select").tooltip({
left: 25
});
</script>

<!-- When moving the mouse over the below options -->
<select>
<option>very long option text 1</option>
<option>very long option text 2</option>
<option>very long option text 3</option>
<option>very long option text 4</option>
<option>very long option text 5</option>
<option>very long option text 6</option>
</select>

Tuesday, March 10, 2009

Unicode Support in Web applications

UPDATE: While most of the points below are still true as of March 2014 the one thing you should do is to visit your whole stack for "Unicode" support. For example looking for tomcat you get this.

Regardless which programming language you use and what application server is involved, internationalization (i18n) support is about handling character encoding in a proper way. Below are guidelines to take into account for any combination of WEB Server/Language. Examples are shown for JBoss/Java though.

1. REQUEST ENCODING: Do not touch it in the server side. Do not use request.setCharacterEncoding() if you do not understand the implication. Only the client (browser) knows the supported encoding and it should be the only responsible for setting it. Most of the browsers use "ISO-8859-1" encoding when submitting data but for example using HTML FORM accept-charset attribute this encoding could be different. JBoss (4.0.4-GA at least) will not affect a GET request when request.setCharacterEncoding() is used but it will affect the POST parameters. It is clear that somehow the algorithm used to decode the query string is different than the one used for posted form data. By default, at least in my tests, request.getCharacterEncoding() returns always NULL.

2. REQUEST PARAMETERS PARSING: Browsers will encode "ISO-8859-1" even those characters not supported by that encoding. Be aware of your server limitations. A typical Servlet Container will try to interpret any request as "ISO-8859-1" and so corrupted bytes are going to end up in the String returned by ServletRequest.getParameter(). The good news is bytes can be read from that corrupted string and reencoded with the right encoding (the one you support in your application and I would say it should be 99% percent of the time UTF-8). To correct this issue wrap ServletRequest.getParameter() following http://www.adobe.com/devnet/server_archive/articles/internationalization_in_jrun.html advice. Notice however that it is assumed in that post that Browsers will always use "ISO-8859-1". A safer way is to find the encoding as below:
String requestEncoding = request.getCharacterEncoding();
if(requestEncoding == null || requestEncoding.trim().length() == 0) {
requestEncoding = "ISO-8859-1";
}


If you are using Tomcat you can avoid that all together with a a change in server.xml and the use of a CharacterEncodingFilter. These features should be available in other servers as well. So again use the below which will deal with GET requests:
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
And the below which will deal with POST requests:
<!-- First fileter must be the Set Character Encoding Filter -->
    <filter>
        <filter-name>setCharacterFilter</filter-name>
        <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
            </init-param>
        <init-param>
            <param-name>ignore</param-name>
            <param-value>false</param-value>
            </init-param>
    </filter>
    <filter-mapping>
        <filter-name>setCharacterFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>

3. PROGRAM MANIPULATION: Java has unicode support out of the box but not all classes are privileged to enjoy it. Be careful when working with Properties.class as UTF-8 is not allowed. If UTF-8 support is needed then it must be escaped in properties files. We need then to convert UTF-8 strings into ASCII Java Escaped Unicode. For example the two Asian characters string "中医" (URL Encoded version: %E4%B8%AD%E5%8C%BB) should be converted to \u00ef\u00bb\u00bf\u00e4\u00b8\u00ad\u00e5\u0152\u00bb removing all but the first "\u" before using Properties#load() . There is a project with source code available that can be used to work around
this issue (https://advancenative2asciitool.dev.java.net/). Below is a class that turns the Unicode characters into ASCII Java Escaped Unicode:
/**
* All credits for the "Advance Native2ASCII Tool" from https://advancenative2asciitool.dev.java.net/
*/

package com.bittime.util.design;

/**
* Please refer to http://en.wikipedia.org/wiki/ASCII for definition on valid/printable ASCII characters
*/
public class Unicode2ASCII {

public static String toHTML(String unicode)
{
String tc = unicode;
String output = "";

char[] ca = tc.toCharArray();
int x;

for( x = 0; x < a =" ca[x];">126){
output += "&#" + (int)a + ";" ;
}
else{
output += a ;
}
}

return output;
}

public static String toJAVA(String unicode)
{
String tc = unicode;
String output = "";

char[] ca = tc.toCharArray();
int x;

for( x = 0; x < a =" ca[x];">255){
String hexString = "0000" + Integer.toHexString((int)a);
hexString = hexString.substring(hexString.length() - 4);
output += "\\u" + hexString ;
}
else{
output += a ;
}
}

return output;
}
}


4. RESPONSE HEADERS: An HTTP header (Content-Type) is responsible to give the client (Browser) the encoding used in the response. A typical example is "Content-Type: text/html; charset=UTF-8". The response content type then must be set not only with the mime type you want but in case of any text mime type the proper charset must be specified as well.

From JSP for example:
<%@page contentType="text/html; charset=UTF-8" %>
From Java:
response.setContentType("text/html; charset=UTF-8");

There is no need to call response.setCharacterEncoding() if setContentType() is called passing both the mime type (text/html) and the encoding (charset). If response.setCharacterEncoding("UTF-8") is used then still setContentType("text/html")must be called. Refer to http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletResponse.html#setCharacterEncoding(java.lang.String) for more explanation.

If you can identify if the request should be served as html in a Servlet Filter then it is a good idea to build a Unicode filter that will force the response to be UTF-8 for those requests:
public class UnicodeFilter implements Filter {


 public void doFilter(ServletRequest request, ServletResponse response,
   FilterChain chain) throws IOException, ServletException {
  response.setContentType("text/html; charset=UTF-8");
  chain.doFilter(request, response);
 }

 public void init(FilterConfig arg0) throws ServletException {
 }
 
 public void destroy() {
 }

}

5. RESPONSE CONTENT: Of course you must ensure all the body of the HTTP response uses the specified by RESPONSE HEADER encoding. This is not a big problem in Java but again there are subtle problems you need to be aware of. It is common for example to use JSP to specify markup. If the HTML included in the JSP needs non-ascii unicode characters then the encoding of the file must be the same as the one used in the responses AND as explained before an @page directive with contentType specified in it is required in absolutely all JSP pages. Add to the equation any file touched by building tools regardless if you use Maven, Ant, Make, Shell, manual, you-name-it methods. Any piece of information returned after the HTTP headers must be encoded as dictated by "Content-Type" header. So my advice is encode all your source files in UTF-8 if you need to support internationalization in your application. Finally, be sure your Server is running with default encoding set to UTF-8. Commonly this is not a problem in current versions of Linux where the default charset is precisely "UTF-8" but Windows uses "ISO-8859-1". In the case of Java Applications use the below when starting the server:
-Dfile.encoding=UTF-8
Particularly for JBoss Windows for example:
set JAVA_OPTS=-Dfile.encoding=UTF-8 %JAVA_OPTS%

You can always check from JSP the server encoding:
%=System.getProperty("file.encoding")%>

6. DEFAULT RESPONSE ENCODING: There are server specific configurations that will free the developer from setting the charset of the response. I do not recommend them since they break portability and might end up generating other problems related to internationalization.

7. BROWSER / OS language support: Firefox for example comes with support for all languages however Internet Explorer does not. Commonly WXP users running IE will need to install language support for Chinese and Thai, Font support in IE is tricky (Internet Options|General|Fonts|Latin Based;Times New Roman OR Arial;Courier New is a good selection, any other is not good for Unicode support), support for Assian languages must be selected manually (Control Panel | windows Regional and Language Options | Install files for 'East Asian Languages')

8. FILE ENCODING: If developers use Windows and Linux then default encoding in their Editors will be an issue. Linux uses UTF-8. Do not use non-ASCII characters in code if you are not able to force the use of UTF-8 from editors. If specific non ASCII code is needed for String comparison for example you can use escaped UTF-16 sequences for example in Java instead of ÀÁÂÃÄ use \u00c0\u00c1\u00c2\u00c3\u00c4

Here is an excellent Unicode table.

9. JDBC: If you are interacting with your database which is already storing UTF-8 successfully then it is time to tell your driver to use Unicode as well. Here is a typical URL for MySQL:
jdbc.url=jdbc:mysql://localhost:3306/myDB?Unicode=true&characterEncoding=UTF-8


10. FRAMEWORKS: Look for support of Unicode if you are using a specific Framework. For example in Spring org.springframework.web.filter.CharacterEncodingFilter will encode requests and responses.

Wednesday, March 04, 2009

Building Web Services Clients

When building Web Services (SOAP WS) clients in Java or any other language there are a couple of good tools to get familiar with before you drop your first line of code.

The two needed tools are a MockUp service that can be built from the WSDL of the remote web service and an HTTP Sniffer. While you can find similar tools written in a variety of languages the two that I am presenting hereare written in Java and thanks to that they run in any major OS out there by this time.

No matter what you use (DotNet client, RoR client, PHP Client, Spring-WS, AXIS2, AXIS, etc) the steps below should help you.

Prerequisites
1. SOAPUI
1. tcpmon

Use Cases
Writting use cases is important so you know every detail as to how your application should work. They are also a perfect initial documentation that even if outdated in the future at least gives other developers comming after you or even to yourself a reminder as to what the application does.

Building the Mockup Services (necessary to simulate Use Cases)
1. Start from understanding the services and ending points we will use from the remote service. In other words visit the WSDLs (for example https://domain/some/path/descriptor?wsdl)
2. Use SOAPUI to create a new project giving the WSDLs (File|New Project|Provide WSDL and a name|Check "Create Requests" and "Create MockService").
3. Locate from the Request group the remote method to invoke and double click on "Request 1". Complete the request parameters if any and click on the "Run" button
4. Right click on the root of the resulting entry on the right panel and click on "Generate MockService". Locate from the MockService group the remote method to invoke and double click on "Response1"
5. Copy the response text from the right pane of the request window into the right pane of the response window.
6. Repeat the above for any single method you want to Mock up (simulate)
7. Double click on the MockService group (or right click and select "Show MockService Editor"). Hit the "Run" button and the service will be available on port 8088
8. At this point from the Request window the address can be changed to point to the local Mock Service listening on port 8088. Hit the green button called "Submit request ...". The right pane should show up  whatever the Response window right pane contains

Using tcpmon

This is a java utility which comes with Axis (not Axis2). To run it use something like:

AXIS_LIB="/home/nurquiza/libraries/axis-1_4/lib"
CLASSPATH="$AXIS_LIB/wsdl4j-1.5.1.jar:$AXIS_LIB/axis.jar:$AXIS_LIB/jaxrpc.jar:$AXIS_LIB/commons-logging-1.0.4.jar:$AXIS_LIB/commons-discovery-0.2.jar:$AXIS_LIB/saaj.jar"
java -cp $CLASSPATH org.apache.axis.utils.tcpmon 8081 localhost 8088 &

With the commands above you get a window where you can see the TCP traffic going back and forth to port 8081. That port is proxing port 8088 meaning that requests to made to 8081 are actually forwarded to 8088.
Just go back to SOAPUI and click on any "Request 1" window address bar, pick the local address of the mockup service. Click again on the address bar and select "edit current", change the port number to 8081. After hitting the 'Run' button you can see the response on SOAPUI but you can also get the whole request and response including HTTP headers from tcpmon. Of course this is not that useful because you have all that information from SOAPUI already but when you start building your client you will not longer see your requests on SOAPUI.

Tuesday, March 03, 2009

DotNet Web Services From Axis2

I had to connect recently to some DotNet Web Services that were returning node names starting with an upper case (as a difference with Java where nodes start with lower case as Java class members do). I already posted a project about this but just wanted to conclude here.

This situation generates a problem at least forthe latest Axis2-1.4.1 which will be unable to dynamically deserialize the response (Assumming BeanUtil#deserialize() is used here). I have described this problem (http://markmail.org/message/2d2r7qlwnoeqka5m) in the mailing list (org.apache.ws.axis-dev).

For unmarshalling or deserializing XML into Java objects there are several Object-to-XML mapping (OXM) libraries: JAXB, JiBX, XMLBeans, Castor, XStream. Most of them are supported by Spring Web Services (Spring-WS) which provides a full stack to build and consume web services.

Another solution is going low level and use SAX (Simple API for XML), StAX (the streaming API for XML).

I have successfully worked around this issue using JAXB. The only reason that stopped me from using Sprint-WS was to stick to the old implementation code for the client (written using ADB stubs)

Using JAXB
1. Download JAXB and follow instructions from the site.
2. From the JAXB lib folder generate the classes from schema like in:
java -jar jaxb-xjc.jar -p com.nestorurquiza.axis2.samople.client.jaxb "https://mydomain/some/path/serviceShema.xsd" -d /path/to/project/client/jaxb/
3. You end up with generated classes that can be used from the client code to unmarshal the SOAP service response into Java objects. Below is a snippet as to how to get it working starting from an OMElement (Refer to my previous tutorial about Axis2 Dynamic Web Services). We are marshalling 'SampleObject' below. Note that SampleObject' is actually a class generated from the schema as explained before:
import org.apache.axiom.om.OMElement;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import java.io.Reader;
import java.io.StringReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import com.nestorurquiza.axis2.sample.client.jaxb.SimpleObject;

...
//AXIOM stuff ...
OMElement result = sender.sendReceive(sampleObjectPayload);
OMElement firstElement = result.getFirstElement();
//The data element is a child of the first element for this example
OMElement dataElement = firstElement.getFirstElement();

//JAXB stuff ... Contextualize JAXB within the package holding the generated from schema sources
JAXBContext jc = JAXBContext.newInstance("com.nestorurquiza.axis2.sample.client.jaxb");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Reader reader = new StringReader(dataElement.toString());
Source source = new StreamSource(reader);
//JAXB always unmarshals to a JAXBElement. Notice the below will work even if the XML node has a different name than the class.
//If the node and the class are named the same then just use SampleObject sampleObject = unmarshaller.unmarshal(source); instead.
JAXBElement root = unmarshaller.unmarshal(source, SampleObject.class);
SampleObject sampleObject = root.getValue();
//Let us retrieve one of the members from our 'SampleObject'. Note the use of getValue().
String sampleObjectMember = sampleObject.getSampleObjectMember().getValue();
//We can use our String member now
System.out.println("sampleObjectMember: " + sampleObjectMember);

...

Again, should the current Axis2 Axiom API work with node names starting with upper case we should have avoid all of the above JAXB code and just use:


SampleObject sampleObject = (SampleObject) BeanUtil.deserialize(SampleObject.class, dataElement, new DefaultObjectSupplier(), "SampleObject");
Dependencies
Here are the dependencies I successfully used:
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.axis2</groupId>
            <artifactId>axis2-adb</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.ws</groupId>
            <artifactId>jaxws-tools</artifactId>
            <version>2.1.3</version>
        </dependency>

Axis2 Dynamic Binding Tutorial

My previous post was dealing with the dynamic consumption of a SOAP Web Service using Axis (JAX-RPC).

A web service can be dynamically consumed (Without the generation of static stubs) from Axis2 (JAX-WS) as well through the use of AXIOM.

I have written a tutorial explaining how to do it.

Again the advantage of going this path is just about solving issues when unexpected changes occur on the server side and there is no contract with the service provider to be informed of those changes before the release.

A simple extra complex type in the response will make the SOAP client to fail if it was generated using static stubs, hence the need for a dynamic binding solution.

Followers