Saturday, October 16, 2010

Saving precious Android Market description text space

Pretty annoying that you only have 325 characters in the description field when submitting an app right? You really have to use the space wisely.

One of the things you usually want to put in what you have added/changed in the current release, so people who want to update know what to expect.
That takes up precious space of those 325 characters. But from now on you don't need to worry about that anymore because... it turns out you can put any text in the android:versionName attribute in the AndroidManifest.xml!

So what I usually do is put in versionName the digits from the android:versionCode attribute separated by dots, then a space and then a short description of what has changed since the last version. For example, suppose android:versionCode="103" then androidName becomes:

android:versionName="1.0.3 Preferences are now correctly stored"

So what does it look like? Well here's first a screenshot of an app that only puts in a version number in the android:versionName attribute:


And here's an example of an app that fully uses that attribute:


I do not know what the maximum lenght is of the versionName field, but apparently you can put quite some text in there, as can be seen from above screenshot.

Update: well, putting the version information in the versionName is not necessary anymore, since from now on there's a separate field to put the recent changes into. What now quickly comes to mind to put into the versionName could be the minimal SDK version number your app supports. That can be useful for people who want/need to get your app on non-Google markets. This way they get at least an indication whether the app can run on their phone or not.

Update: and recently (definitely since 23 Feb 2011) they have limited the length of the versionName field to 30 characters, because if you exceed that, at apk-upload time you'll see: "The versionName in AndroidManifest.xml exceeds maximum (30)."

Sunday, October 3, 2010

JBoss Application Server 5.1/ESB 4.5 GA and ActiveMQ 5.4 integration

On one of my last projects I had to integrate JBoss ESB 4.5 GA with ActiveMQ 5.4.0 and Spring 3. NOTE: the fixes below also work for integration with JBoss 5.1 Application Server.



My starting point was of course this post: Integrating Apache ActiveMQ with JBoss. (Or is this the original?)
Part of the requirements mentioned in that article (Apache ActiveMQ 4.0.1+ and JBoss 4.0.4+) got me worried that the steps described might not work for my version of JBoss and ActiveMQ. Even though there's a '+' after the version numbers :)

First I had quite a hard time finding the .rar file! Finally found it in \lib\optional in the ActiveMQ zip: activemq-rar-5.4.0.rar

After that I followed the steps including up to 'Configuring JBoss'. In there you also have to start JBoss again.
I didn't see any exceptions fly around so thought all was fine, so I started the consumer ('ant consumer').
But there I got:



[java] javax.jms.JMSException: Could not connect to broker URL:
tcp://localhost:61616. Reason: java.net.ConnectException:
Connection re[Thread-2] Caught: javax.jms.JMSException: Could not
connect to broker URL: tcp://localhost:61616. Reason:
java.net Connection Exception : connection refused


Strrrange, because I thought the server started fine. After quite some searching, I figured out the error message probably indicates that there's just nothing listening at localhost:61616.
After carefully checking the startup log (searching for 'activemq') I found out it hadn't started!



17:17:31,566 INFO [XBeanXmlBeanDefinitionReader] Loading XML bean
definitions from class path resource [broker-config.xml]
17:17:31,768 WARN [ActiveMQResourceAdapter] Could not start up embeded
ActiveMQ Broker 'xbean:broker-config.xml': Line 29 in XML document from
class path resource [broker-config.xml] is invalid; nested exception is
org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration
of element 'beans'.


That's weird, some namespace problem?
Searching on the biggg internet I found this page (via), explaining that the namespaces are different from 5.1 onwards.

Since I'm using AMQ 5.4.0 I tried in broker-config.xml:



<beans xmlns="http://activemq.apache.org/schema/core">


But that still gave:



17:23:38,638 WARN [ActiveMQResourceAdapter] Could not start up embeded
ActiveMQ Broker 'xbean:broker-config.xml': Line 29 in XML document from
class path resource [broker-config.xml] is invalid; nested exception is
org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration
of element 'beans'.


So now I just tried all the namespace definitions:



<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.2.0.xsd
">
</beans>


Darn, still not ok:



17:27:42,265 WARN [ActiveMQResourceAdapter] Could not start up embeded
ActiveMQ Broker 'xbean:broker-config.xml': Line 49 in XML document from
class path resource [broker-config.xml] is invalid; nested exception is
org.xml.sax.SAXParseException: cvc-complex-type.2.4.c: The matching wildcard
is strict, but no declaration can be found for element 'persistenceAdapter'.


But that was easy, missing the namespace prefix. So I modified:



<amq:persistenceAdapter>
<amq:journaledJDBC journalLogFiles="5" dataDirectory="activemq-data"/>
<!-- To use a different datasource, use th following syntax : -->
<!--
<journaledJDBC journalLogFiles="5" dataDirectory="../data" dataSource="#postgres-ds"/>
-->
</amq:persistenceAdapter>


But again an error:



17:29:50,840 WARN [ActiveMQResourceAdapter] Could not start up embeded
ActiveMQ Broker 'xbean:broker-config.xml': Line 50 in XML document from
class path resource [broker-config.xml] is invalid; nested exception is
org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was
found starting with element 'amq:journaledJDBC'. One of
'{"http://activemq.apache.org/schema/core":amqPersistenceAdapter,
"http://activemq.apache.org/schema/core":jdbcPersistenceAdapter,
"http://activemq.apache.org/schema/core":journalPersistenceAdapter,
"http://activemq.apache.org/schema/core":kahaDB,
"http://activemq.apache.org/schema/core":kahaPersistenceAdapter,
"http://activemq.apache.org/schema/core":memoryPersistenceAdapter,
WC[##other:"http://activemq.apache.org/schema/core"]}' is expected.


So journaledJDBC is unknown. There must be something with a wrong namespace version or something. From the XSDs from here it seemed there was an element in the wrong place. So I just removed the whole persistenceAdapter element.

I also noted that there is a persistenceFactory element in the AMQ 450 broker-config.xml, which is not present in the Integrating Apache ActiveMQ with JBoss post.
So I also changed that one's dataDirectory to be the same as in the (just removed) persistenceAdapter:



<amq:persistenceFactory>
<amq:journalPersistenceAdapterFactory journalLogFiles="5" dataDirectory="${jboss.server.data.dir}/activemq"/>
</amq:persistenceFactory>


Yes that did it! See the log part below:



17:45:01,215 INFO [XBeanXmlBeanDefinitionReader] Loading XML bean definitions
from classpath resource [broker-config.xml]
17:45:01,542 INFO [DefaultListableBeanFactory] Pre-instantiating singletons
in org.springframework.beans.factory.support.DefaultListableBeanFactory@157402b:
defining beans [org.apache.activemq.xbean.XBeanBrokerService#0]; root of
factory hierarchy
17:45:01,697 INFO [PListStore] PListStore:activemq-data\bruce.broker1\tmp_storage
started

... stuff deleted ...

17:45:02,896 INFO [BrokerService] ActiveMQ 5.4.0 JMS Message Broker
(bruce.broker1) is starting
17:45:02,911 INFO [BrokerService] For help or more information please
see: http://activemq.apache.org/
17:45:03,083 INFO [SchedulerBroker] Scheduler using directory:
activemq-data\scheduler
17:45:03,145 INFO [JournalPersistenceAdapter] Journal Recovery Started from:
Active Journal: using 5 x 20.0 Megs at: C:\jbossesb-server-4.5.GA\bin\${jboss.server.data.dir}\activemq\journal
17:45:03,176 INFO [JournalPersistenceAdapter] Journal Recovered: 0 message(s)
in transactions recovered.
17:45:03,207 INFO [TransportServerThreadSupport] Listening for connections at:
tcp://localhost:61616
17:45:03,223 INFO [TransportConnector] Connector bruce.broker1 Started
17:45:03,223 INFO [BrokerService] ActiveMQ JMS Message Broker (bruce.broker1,
ID:PC555-4930-1389432149-0:0) started


Also after that the consumer and producer worked fine.

And as a final optimization to not having to change the namespace for each new ActiveMQ version, I removed the version from the activemq-core xsd:



<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd
">


To summarize, this is the final broker-config.xml (some comments deleted for space):



<?xml version="1.0" encoding="UTF-8"?>
<!-- START SNIPPET: xbean -->
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core.xsd
">

<!-- shutdown hook is disabled as RAR classloader may be gone at shutdown -->
<amq:broker useJmx="true" useShutdownHook="false" brokerName="bruce.broker1">

<amq:managementContext>
<!-- use appserver provided context instead of creating one,
for jboss use: -Djboss.platform.mbeanserver -->
<amq:managementContext createConnector="false"/>
</amq:managementContext>

<amq:persistenceFactory>
<amq:journalPersistenceAdapterFactory journalLogFiles="5" dataDirectory="${jboss.server.data.dir}/activemq"/>
</amq:persistenceFactory>

<amq:transportConnectors>
<amq:transportConnector name="bruce.broker1" uri="tcp://localhost:61616" discoveryUri="multicast://default"/>
</amq:transportConnectors>

</amq:broker>
</beans>


JBoss 5.1 AS specific stuff:

I just copied over the above created .rar dir to the jboss-5.1.0.GA/server/default/deploy/activemq-ra.rar/META-INF directory and started it.

Got one error trying:



18:00:48,611 ERROR [AbstractKernelController] Error installing to Parse:
name=vfsfile:/C:/jboss-5.1.0.GA/server/default/deploy/activemq-ra.rar/
state=Not Installed mode=Manual requiredState=Parse
org.jboss.deployers.spi.DeploymentException: Error creating managed object
for vfsfile:/C:/jboss-5.1.0.GA/server/default/deploy/activemq-ra.rar/
at org.jboss.deployers.spi.DeploymentException.rethrowAsDeploymentException(
DeploymentException.java:49)
...
Caused by: org.jboss.xb.binding.JBossXBException: Failed to parse source:
cvc-complex-type.2.4.d: Invalid content was found starting with element
'config-property-value'. No child element is expected at this point. @
vfsfile:/C:/jboss-5.1.0.GA/server/default/deploy/
activemq-ra.rar/META-INF/ra.xml[100,36]


Ah for some reason I had an empty in ra.xml. Removing that made the 5.1 server start fine and the producer produce and the consumer consume!

PS: the example consumer & producer now send out 2000 messages instead of the 10 you see in the Integrating Apache ActiveMQ with JBoss post.

Hope this might help somebody some time :)

Changing format of blog

This blogpost is the last of the 'Best of this Week Summary' series.
Looking at the number of subscribers, I decided it's too low to be worth the effort.

Therefore, from now on I'll only post "real" blogposts written by myself, no more weekly summaries.
Those posts will contain lessons learned, tutorials etc.
This change of format also implies that the posts will be less frequent but hopefully much more interesting and relevant to a greater audience.

For the fans, here's the last set of items for "Best of this Week Summary", 27 September - 3 October 2010:


PS: I'll change my mind if I get at least 50 (valid, unique) requests in the comments to keep posting my weekly summaries :)