Thursday, June 19, 2008

MiniIM in Action




I am really enjoying the development, Here is how it looks currently.

KXML skip SubTree skip Depth

KXML is just the name of XML parsing in J2ME. As I am using it in MiniIM, parsing XMPP and even special markup, I found it useful to skip upto a specific depth of XML tree. Note, the skipSubTree() method in KXMLParser / XMLPullParser API is useful. But it needs that you call it at tag start otherwise it will throw exception. So I introduce skipDepth(depth) idea. You just set your depth upto which you want to skip. It will just eat data upto that.

For example here is a small part of stream,

<?xml version='1.0'?>

<stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" id="1523376107" from="jabber.org" version="1.0" xml:lang="en">

...
...
<stream:features>
<mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
<mechanism>DIGEST-MD5</mechanism>
<mechanism>PLAIN</mechanism>
</mechanisms>
<register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>

...
...

Here is the simple code to parse the "stream:features",

final void readFeatures() throws IOException {
String tagName;
String text;
parser.nextTag();
parser.require(KXmlParser.START_TAG, null, PREFIX_FEATURES);

for (; parser.nextTag() != KXmlParser.END_TAG; parser.skipDepth(3)) { /* The features tag is placed at depth 1 */
/* we are parsing things inside this feature tag */
tagName = parser.getName();
if (tagName == null) {
throw new IllegalStateException("feature is null");
} else if (tagName.equals(STARTTLS)) {
/* set a starttls read command */
SimpleLogger.debug(this, "<" + STARTTLS);
featuresTLS = true;
} else if (tagName.equals(MECHANISMS)) {
/* traverse the mechanisms inside */
SimpleLogger.info(this, "readFeatures()\t\tparsing mechanisms");
/* so while inside the mechanisms */
for (; parser.nextTag() != KXmlParser.END_TAG;parser.skipDepth(5)) {
tagName = parser.getName();
if (tagName.equals(MECHANISM)) {
/* see if the mechanism is PLAIN */
text = expectText();
if (text == null) {

} else if (text.equals(PLAIN)) {
/* say that plain mechanism is found */
SimpleLogger.info(this, "<" + PLAIN);
featuresPlain = true;
} else if(text.equals(DIGEST_MD5)) {
SimpleLogger.info(this, "<" + DIGEST_MD5);
featuresDigestMd5 = true;
}
/* do not break, go on parsing mechanisms */
}
}
} else if (tagName.equals(BIND)) {
SimpleLogger.debug(this, "<" + BIND);
featuresBind = true;
} else if(tagName.equals(COMPRESSION)) {
// QUOTE "the ZLIB compression algorithm is mandatory-to-implement"
featuresZLIB = true;
/* traverse the mechanisms inside */
SimpleLogger.info(this, "readFeatures()\t\tparsing compression");
for (; parser.nextTag() != KXmlParser.END_TAG;parser.skipDepth(5)) {
tagName = parser.getName();
if (tagName.equals(METHOD)) {
String compressionMethod = expectText();
if(compressionMethod != null && compressionMethod.equals(ZLIB)) {
featuresZLIB = true;
}
}
}
} else {
SimpleLogger.debug(this, "<!" + tagName);
/* whatever it is just finish the tag */
}
SimpleLogger.debug(this, "< next");
}
parser.skipDepth(2);
}
}


And here is the small method I have added in KXMLParser.

public void skipDepth(int dep) throws IOException,XmlPullParserException {
int level = getDepth() - dep;
int eventType = getEventType();

if(eventType != KXmlParser.END_TAG) {
level++;
}

while(level > 0) {
eventType = next();
if (eventType == KXmlParser.END_TAG) {
--level;
}
else if (eventType == KXmlParser.START_TAG) {
++level;
}
}
}


I hope it helps :) ..

Wednesday, June 18, 2008

Shrink wurfl mobile database

WURFL is nice mobile database. The j2mepolish database is good too. Anyway I was trying to use wurfl.xml file(you can download it from wurfl homepage) while releasing my j2me application. But as the wurfl.xml file is too big(4.3M), I have removed some unused attributes and tags from it. And still I am able to use the parsers (I tested only the perl parser :-P ). Finally the size is reduced to (1.4M) .

My primary goal is to resize some of my background images appropriate to the the screen resolution for a specific mobile. So I filtered the resolution_width and resolution_height information.

Here is the small xslt code used to shrink the wurfl.xml .

<?xml version="1.0" ?>

<!--

This file part of MiniIM.

Copyright (C) 2007 Kamanashis Roy

MiniIM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

MiniIM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with MiniIM. If not, see <http://www.gnu.org/licenses/>.

-->


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:output method="xml" indent="yes"/>

<!-- select the device tag -->
<xsl:template match="/wurfl">

<wurfl>
<xsl:copy-of select="version"/>
<devices>
<xsl:apply-templates select="devices/device"/>

</devices>
</wurfl>
</xsl:template>

<!-- process devices -->
<xsl:template match="device">

<device fall_back="{@fall_back}" id="{@id}" user_agent="{@user_agent}">
<!-- keep only display group -->

<xsl:apply-templates select="group[@id='display']"/>
</device>
</xsl:template>

<xsl:template match="group">

<!-- render non empty group -->
<xsl:if test="count(capability[@name='resolution_width'])=1">
<group id="{@id}">

<xsl:apply-templates select="capability[@name='resolution_width']"/>
<xsl:apply-templates select="capability[@name='resolution_height']"/>
</group>

</xsl:if>
</xsl:template>

<xsl:template match="capability">
<capability name="{@name}" value="{@value}"/>

</xsl:template>

</xsl:stylesheet>



Now let us do the transform, I have used xsltproc for the transform here, you may want to get xsltproc binary for your os or get source here. And you can apply transform like this,

shell> xsltproc your_shrinker.xslt wurfl.xml > wurfl_shrinked.xml

You can do some appropriate modifications to this code to keep some other attributes too. I prefer to write separate xsl code for each application. Note there are other alternatives, like database
usage available in wurfl site. So please read those docs before trying this :) .

Finally I used the cool perl module form imagemagick to resize my images :) .

Enjoy !