Thursday, October 14, 2010

Sub pixel chromium

I have been trying to get one particular div to show up on my page for ages now. It shows fine in Firefox but not in chrome. After some red herrings around opacity (aka webkit-opacity), I finally figured out what the issue was, good old border width!

Apparently this works in FF but not in chrome: border-width: 0.1px;

Changing it to this makes both browsers ignore it and put a border of 1 px: border-width: 0.1 px;

This is what finally made it work: border-width: thin;

Hmm, so that gives me what I want, but now curious if FF does really support sub-pixel borders as a real valued function? Actually, it doesn't. It just assumes anything less than 1 pixel as "thin". It behaves even more weirdly when values are greater than one, need to investigate it a little more in detail.

Of char, int and unicode

So my overflowing smartness and largely my ignorance made me believe that I could convert a HTML encoded string into UTF8 by doing a normal split and join. Something like this:

String testStr = "呀数达";
String[] splitStr = testStr.split("&#");
StringBuilder bldr = new StringBuilder();
for (String str : splitStr)
{
str = str.replace(";","");
bldr.append("\\u"+Integer.toHexString(Integer.valueOf(str)));
}

So I was thinking that a string like this "\u1234\u2345\u3456" as created is what I was looking for.

Well, WRONG! The thing is the string as written above is of length 3 (each set of \uxxxx is treated as one character) and what I was creating was a string of length 18. So how do I fix this? I ended up doing something I never thought I would, casting an int as char!

The way characters are stored is they are stored as their int representations and hence, that is what would make it work. So my code now looks like:

String testStr = "呀数达";
String[] splitStr = testStr.split("&#");
StringBuilder bldr = new StringBuilder();
char chr;
int i;
for (String str : splitStr)
{
str = str.replace(";","");
i = Integer.valueOf(str);
chr = (char) i;
bldr.append(chr);
}

Thursday, October 7, 2010

Of JNDI, DBCP and Oracle

In continuation with the earlier post, I was pretty close to hitting my head against a big, indifferent wall as I struggled with JNDI connections and Oracle Prepared Statement to dump in Chinese characters into a database column.

So here's the step by step account:
  • Make sure your database column type is NVARCHAR2. This is just like VARCHAR2 but allows you to insert pretty much everything into it.
  • Query up your national character set: select value from v$nls_parameters where PARAMETER = 'NLS_NCHAR_CHARACTERSET'. This should return AL16UTF16
  • Now the first option is to use the unistr function. So my statement would look something like insert into table_name (col1, col2, col3...,coln) values (?,?,?,...unistr(?)).Now use a standard setString API call, but make sure that the input string is of the form \[four digit hex code] for each character.
  • Second option is to call the setFormOfUse API on the OraclePreparedStatement class as ps.setFormOfUse([index], OraclePreparedStatement.FORM_NCHAR) and set the string in a standard fashion. However, the string here needs to be of the form \u[four digit hex code] for each character.
However, on the last step I kept getting a class cast exception whenever I tried getting the OraclePreparedStatement object from the standard PreparedStatement. This is what you will expect to work normally:

DelegatingPreparedStatement dps = (DelegatingPreparedStatement) ps;
OraclepreparedStatement ops = (OraclePreparedStatement) dps.getInnermostDelegate();
ops.setFormOfUse(...);

But inspite of the runtime class of the object returned by the getInnerMostDelegate() method is OraclePreparedStatement, it kept giving me a class cast exception (I still don't know why!). However, a reflective call like the one below worked!

DelegatingPreparedStatement dps = (DelegatingPreparedStatement) ps;
Statement stmt = ps.getInnermostDelegate();
Method setUsageMethod = stmt.getMethod("setFormOfUse", int.class, short.class);
setUsageMethod.invoke(stmt, [args]);

Now I need to revisit the search implementation on the nvarchar column and then post this to other databases. Hmmph!

Wednesday, October 6, 2010

Unicode and HTML

I have been struggling with developing a sample application in Chinese for the past few days. Its a pretty simple app, add, search and edit employees. Well, not quite!

After building the sample pages, a search and list page and an add / edit page, I tried converting them into Chinese. Here's what I learnt till now:

  1. Don't forget to set pageEncoding tags in jsps. Had to set this to UTF-8 in conjunction with the meta charset tag.
  2. JavaScript understands Unicode strings in hex as \u, HTML needs it as &#;. So if I use hex strings in tags, it works, but same in an AJAX response makes the browser ignore it, they will show up as \u. Need to convert them into decimals.
  3. understands HTML encoded Unicode too (the decimal strings).
  4. IE has troubles understanding charset of a a HTTP post request. In spite of setting charset and encodings, it continues to treat it as windows specific or ISO-8859-1. The hack? Add a hidden variable in your form thats denotes a character not part of the standard encoding (any Cyrillic value will do!) and IE starts responding. Bizarre!
  5. Data posted by the form will most always be HTML encoded. Even if it is stored in DB as such the browser is able to pick it up correctly.
  6. For resource bundles, use the java native2ascii command. Store your files with native characters first, then run this tool as "native2ascii -encoding UTF-16 [input file] [output file]" and you're done!
  7. One form refused to post data in HTML encoded form. The hack? Forcefully converted it such (code below).
  8. Yet to fix the NCHAR / NVARCHAR storage :(

So how do you convert hex to decimal and back?
  • JavaScript: Remember that decimals get prefixed with &# and suffixed with semicolon. The hex prefixed with \u
  1. Try the charCodeAt() built in function. Take a string, iterate over it and call this function for each char.
  2. Hex to decimal using [str].parseInt(16)
  3. Decimal to hex using parseInt([str],16)
  • Java: Similar conversions, Integer.parseInt(str, 16) and Integer.toHexString(int)
Now need to figure out the nchar, nvarchar storage and Im done!

Monday, October 4, 2010

Mocking classes using EasyMock

Before I jump into the post, those who aren't familiar with unit testing, JUnit and TDD should probably do a little read up:

http://en.wikipedia.org/wiki/Test-driven_development : Test driven development with links to other related articles.

As good as a concept it is, it runs into difficulties when your class becomes dependent on several other classes. Thats where mocking comes in, where you create a mock object and make it behave in a particular fashion. The idea here being that when you are testing some class, say ClassA, you expect the dependent classes ClassB and ClassC to behave in a certain fashion. So you create mocks of these classes, making them behave exactly as you expect these classes to at runtime.

I have tried using jMock as library to do the same, but it suffers from the disadvantage that you cannot mock classes. Its pretty straightforward to mock interfaces but unfortunately (although thats how it should be most times), interactions between classes are not always defined via interfaces. So well, the whole testing project was abandoned because of class dependencies.

Then some days ago, I bumped into Google CodePro Anaytix ( http://code.google.com/webtoolkit/tools/codepro/doc/index.html : an awesome plugin btw, more posts on it soon) and its usage of EasyMock (http://easymock.org/) for mocking and interestingly it had class mocking available.

So let me jump into some code directly. Here's my scenario:
  • I have to test a class, say XyzBaseDB, a helper class used for some database extensive rollup programs.
  • It takes a class DatabaseConnection, a wrapper database connection class as its constructor.
  • The wrapper by itself extends another class that takes care of common connectivity operations like JNDI lookup etc.
  • The class implicitly calls the getMetadata() function to get hold of the database metadata.
  • On the metadata it uses the database product name to switch between database specific functions (like dual as system table for oracle and sysibm.sysdummy1, etc.)
Now I need to test a method called getSequence that takes two arguments the name of the sequence and the name of the sequence alias as inputs to return the sql statement which when executed will give the next value from the sequence.

So what I really need to do is:
  • Create an instance of XyzBaseDB with a mock DatabaseConnection object
  • The mock object should return a mocked java.sql.Connection object such that when getDatabaseProductName() method is called on its meta data, it should return "Oracle" as the value
  • This will trigger the Oracle specific code within the getSequence(..) method that I want to test
So here's what I did:
  • Created a factory class (rather codepro did) to get a specific DatabaseConnection object
  • Added the following code within it. Note that I am using the EasyMock class within the classextension directory:
//First mock databasemetadata to mock an Oracle connection DatabaseMetaData md = EasyMock.createMock(DatabaseMetaData.class);
expect(md.getDatabaseProductName()).andReturn("Oracle");
replay(md);

//Mock connection, return mocked metadata for mocked connection Connection conn = EasyMock.createMock(Connection.class);
expect(conn.getMetaData()).andReturn(md);
replay(conn);

//Mock class object, need to use a control here IMocksControl control = EasyMock.createControl(); DatabaseConnection dbConn = control.createMock(DatabaseConnection.class);
expect(dbConn.getConnection()).andReturn(conn);
control.replay(); //replay(dbConn) will fail
return dbConn;
Now any calls on this class will make it work like its an Oracle connection (based on how the code is written). Will keep exploring this to see how it evolves for other use cases as this was pretty straightforward.