Steve On Java

Hacking Java, JavaFX, and Raspberry Pi
  • rss
  • Home
  • SvJugFX
  • 2014 Travel Map
    • 2013 Travel Map
    • 2012 Travel Map
    • Let’s Meetup!
  • Forms
    • Nighthacking Worldwide Beer Reimbursement
    • JFXtras Individual CLA
    • JFXtras Corporate CLA
  • Contact
  • NightHacking.com

Running Liferay on Shared Hosting

steveonjava | June 26, 2009

This is a little off my usual set of topics, but something that hopefully others will find valuable, since there is such little information about this on the net.

Let’s say that you have are launching a new portal website for a Java technology project (such as projavafx.com, and have the following constraints/desires:

  1. You need a site that can handle dynamic content, access controls, forums, blogs, etc.
  2. The underlying portal technology needs to be Java-based.  No way you are hacking PHP (been there, never again…)
  3. You are on a budget.  It is a choice between server hosting and paying your cable bill, and not having the latter would impact your happiness more than the former.

So, with those constraints, you might be brave enough to try putting Liferay Portal on a Shared Tomcat Hosting plan.  Would a dedicated VPS be easier?  Sure, but you also pay more $$$ per bandwidth/disk/cpu.

(I am intentionally not mentioned any hosting companies by name, but if you look around you should be able to find shared Tomcat hosting for under $10/month.)

What to Download

By default Liferay directs you to a self-contained Tomcat installer that will set up a new Tomcat instance from scratch.  You will need to grab this as well as the WAR distribution that is a little bit more buried on the site.  There are also some ancillary downloads, such as the tunnel-web jar that are helpful as well, all of which can be found in the Additional Files section:
http://www.liferay.com/web/guest/downloads/additional

At a minimum you will need:

  • Liferay Portal 5.x Bundled with Tomcat 6.0 (default download)
  • Liferay Portal 5.x WAR

(5.2.3 was the current version at the time of this writing, but feel free to grab the latest and let me know if anything has materially changed by leaving a comment.)

Basic Setup

The default Liferay configuration assumes that you have access to the Tomcat directory and can drop shared libraries and such into the base installation.  This is definitely not possible in a shared environment, so instead we will hack the WAR file to make everything work cleanly instead:

  1. Unpack liferay-portal-tomcat-6.0-5.x.zip
  2. Look for the jar files under tomcat-6.x/lib/ext
  3. Copy all the jar files from that folder into liferay-portal-5.x.war under WEB-INF/lib

Note:  You would think that the Liferay Portal Dependencies jar from the Additional Files section would contain all the jars you need, but it only has a subset.  Unfortunately, the only way to get the full set of jars is by grabbing them from the bundled Tomcat distribution.

The next problem is that you won’t have access to the shared Tomcat context to setup custom context properties.  Fortunately, all of this can be easily configured in a portal-ext.properties file, which is formatted as a standard Java properties file.  Some of the parameters that you will need to use include:

  • portal.ctx – This allows you to set the LifeRay root context if you are running from a sub-folder (which is very common in a shared hosting environment)
  • liferay.home – Folder where liferay will store documents and artifacts.  This should be set to an absolute path within your home folder that is configured to be writable by the Tomcat process.
  • jdbc.default.* – You can set the dirverClassName, url, username, and password that are specific to your hosting environment.

Here is an example portal-ext.properties file:

portal.ctx=/portal
liferay.home=/home/widgetfx/liferay
jdbc.default.driverClassName=com.mysql.jdbc.Driver
jdbc.default.url=jdbc:mysql://localhost/widgetfx_liferay?useUnicode=true&characterEncoding=UTF-8&useFastDateParsing=false
jdbc.default.username=xxxxxxxx
jdbc.default.password=xxxxxxxx

Once you have updated it for your server hosting settings, add it to liferay-portal-5.x.war under WEB-INF/classes.

All that is left is to make sure your database is setup and deploy this WAR file to your hosting provider.  Liferay should come up by itself, or if not check catalina.out for common errors (like database access permissions).

cPanel Tip: If your shared hosting provider uses cPanel to deploy Tomcat applications, you may have trouble getting it to map requests from Apache to Tomcat under the Liferay directory.  An easy way to do this without hacking Apache is to put a .htaccess file under the Liferay root directory with the following contents:

SetHandler jakarta-servlet
SetEnv JK_WORKER_NAME ajp13

Setting up Multiple Instances

All the instructions so far assume you are only setting up one instance (and that no one else has already setup a Liferay instance on the same server).  However, if you want to go multi-instance or just prevent future collisions, some more invasive hacking is required.

Inside of liferay-portal-5.x.war, hidden in portal-impl.jar there is some magical JMX and MBean magic to handle statistcs and configuration that will blow up horribly with multiple instances.  To disable this you will need to:

  • extract WEB-INF/lib/portal-impl.jar
  • inside portal-impl.jar edit META-INF/hibernate-spring.xml and change the statistics key to a unique value (highlighted in bold):
    <entry key="Hibernate:name=statistics">
  • inside portal-impl.jar edit META-INF/messaging-sprint.xml and comment out the JMX bean and reference to it in MessagingConfigurator bean:
    <!--<ref bean="com.liferay.portal.kernel.messaging.jmx.JMXMessageListener" />-->

Once these changes are deployed you can now safely bring up multiple instances as separate Tomcat web applications.

Congratulations, you now have a Liferay instance working on your shared server configuration!

What Next?

While this covers the basics, here are some things that require additional tweaking:

  • Plug-ins cannot be cannot be installed automatically
  • Additional Liferay themes need to be manually deployed
  • Tunnel-web needs to be configured differently

If I am feeling adventurous (and there is interest), I will do a part 2 of this to go over tunnel-web and plug-in/theme configuration in a shared hosting environment.

 

Share this:

  • Twitter
  • Facebook
  • Google
Categories
Liferay
Tags
how-to, Liferay, shared-hosting
Comments rss
Comments rss
Trackback
Trackback

« JFXtras 0.5 Release Announcement WidgetFX 1.2 Release Announcement »

24 Responses to “Running Liferay on Shared Hosting”

  1. nihed says:
    June 26, 2009 at 7:43 am

    You can download additional jar from http://www.liferay.com/web/guest/downloads/additional
    *Liferay Portal 5.2.3 Dependencies
    instead Unpack liferay-portal-tomcat-6.0-5.x.zip

    Reply
  2. Zahid says:
    August 12, 2009 at 4:32 am

    I want to host my liferay on a shared server , can you elaborate on how after making all the changes in the .WAR file ,what are next steps like putting the unzipped liferay bundled tomcat on to the shared server and then deploying the WAR file and how to put my portlet or portlets into the tomcat.

    I have not done any thing like this before so please help.

    Thanks in advance

    Reply
  3. Romualdo says:
    August 19, 2009 at 7:18 am

    Hi, Steve.

    After performing each step, I’ve got the following error:

    09:04:22,765 ERROR [ContextLoader:215] Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘messageListener.scheduler’ defined in class path resource [META-INF/messaging-spring.xml]: Cannot resolve reference to bean ‘com.liferay.portal.kernel.scheduler.SchedulerEngine’ while setting constructor argument;

    The complete log file is:
    ———————–
    Aug 19, 2009 9:03:20 AM org.apache.catalina.core.AprLifecycleListener init
    INFO: The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/local/jdk1.6.0_13/jre/lib/i386/server:/usr/local/jdk1.6.0_13/jre/lib/i386:/usr/local/jdk1.6.0_13/jre/../lib/i386:/usr/java/packages/lib/i386:/lib:/usr/lib
    Aug 19, 2009 9:03:20 AM org.apache.coyote.http11.Http11Protocol init
    INFO: Initializing Coyote HTTP/1.1 on http-12013
    Aug 19, 2009 9:03:20 AM org.apache.catalina.startup.Catalina load
    INFO: Initialization processed in 414 ms
    Aug 19, 2009 9:03:20 AM org.apache.catalina.core.StandardService start
    INFO: Starting service Catalina
    Aug 19, 2009 9:03:20 AM org.apache.catalina.core.StandardEngine start
    INFO: Starting Servlet Engine: Apache Tomcat/6.0.14
    Aug 19, 2009 9:03:20 AM org.apache.catalina.startup.HostConfig deployWAR
    INFO: Deploying web application archive ROOT.war
    Aug 19, 2009 9:03:21 AM org.apache.catalina.startup.HostConfig deployWAR
    INFO: Deploying web application archive liferay.war
    Loading jar:file:/home/romualdo/jvm/apache-tomcat-6.0.14/domains/infociencias.net/liferay/WEB-INF/lib/portal-impl.jar!/system.properties
    Loading jar:file:/home/romualdo/jvm/apache-tomcat-6.0.14/domains/infociencias.net/liferay/WEB-INF/lib/portal-impl.jar!/portal.properties
    Loading file:/home/romualdo/jvm/apache-tomcat-6.0.14/domains/infociencias.net/liferay/WEB-INF/classes/portal-ext.properties
    09:03:30,369 INFO [DialectDetector:64] Determining dialect for MySQL 5
    09:03:30,441 INFO [DialectDetector:97] Using dialect org.hibernate.dialect.MySQLDialect
    Loading jar:file:/home/romualdo/jvm/apache-tomcat-6.0.14/domains/infociencias.net/liferay/WEB-INF/lib/portal-impl.jar!/captcha.properties
    09:03:32,959 INFO [PortalImpl:252] Portal lib directory /home/romualdo/jvm/apache-tomcat-6.0.14/domains/infociencias.net/liferay/WEB-INF/lib/
    09:04:22,765 ERROR [ContextLoader:215] Context initialization failed
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘messageListener.scheduler’ defined in class path resource [META-INF/messaging-spring.xml]: Cannot resolve reference to bean ‘com.liferay.portal.kernel.scheduler.SchedulerEngine’ while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.liferay.portal.kernel.scheduler.SchedulerEngine’: Injection of BeanReference fields failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:275)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:104)
    at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:479)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:162)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:925)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:835)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:440)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:429)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:728)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:380)
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:255)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:199)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
    at com.liferay.portal.spring.context.PortalContextLoaderListener.contextInitialized(PortalContextLoaderListener.java:49)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3830)
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4337)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
    at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:825)
    at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:714)
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:490)
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
    at org.apache.catalina.core.StandardService.start(StandardService.java:516)
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.liferay.portal.kernel.scheduler.SchedulerEngine’: Injection of BeanReference fields failed; nested exception is java.lang.OutOfMemoryError: Java heap space
    at com.liferay.portal.spring.annotation.BeanReferenceAnnotationBeanPostProcessor.postProcessAfterInstantiation(BeanReferenceAnnotationBeanPostProcessor.java:68)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:959)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:472)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:409)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:380)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:264)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:261)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:185)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164)
    at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:269)
    … 45 more
    Caused by: java.lang.OutOfMemoryError: Java heap space
    Aug 19, 2009 9:04:23 AM org.apache.catalina.core.StandardContext start
    SEVERE: Error listenerStart
    Aug 19, 2009 9:04:23 AM org.apache.catalina.core.StandardContext start
    SEVERE: Context [/liferay] startup failed due to previous errors
    log4j:ERROR LogMananger.repositorySelector was null likely due to error in class reloading, using NOPLoggerRepository.
    Aug 19, 2009 9:04:24 AM org.apache.coyote.http11.Http11Protocol start
    INFO: Starting Coyote HTTP/1.1 on http-12013
    Aug 19, 2009 9:04:24 AM org.apache.catalina.connector.MapperListener registerEngine
    WARNING: Unknown default host: localhost
    Aug 19, 2009 9:04:24 AM org.apache.catalina.startup.Catalina start
    INFO: Server startup in 63867 ms
    ————

    Do you know how to solve this problem?

    Thanks in advance,

    Romualdo.

    Reply
  4. Gunnar says:
    August 27, 2009 at 1:00 am

    Hi Steve on Java, and thanks for writing about how to install Liferay on a shared hosted server. Perhaps i have almost the same questions as Zahid but anyway..

    I followed your instructions and steps but want to know more about portal-ext.properties, you wrote:
    “portal.ctx – This allows you to set the LifeRay root context if you are running from a sub-folder (which is very common in a shared hosting environment)”

    Can you explain what i need to install on my shared area on the hosted server, and what is Liferay root context? You mean root.xml, context.xml files?

    To deploy my edited .war file? Is it to send this file to the adminstrator of the hosted server?

    Thanks again!

    /Gunnar

    Reply
  5. karthik says:
    August 31, 2009 at 10:56 pm

    Thanks Steve,
    This article is very help , Steve one more request,is it possible for your you to explain how to deploy new portlets and themes to this shared environment. It will be great if you write an article about this. Thanks

    Reply
  6. Constantin says:
    September 21, 2009 at 9:45 am

    Hi Steve, I have some questions for you related to this post:
    I followed all above settings, I renamed de *.war in liferay-portal.war and tomcat deployed this archive in liferay portal… Now I’m trying to test the portal in windows, and, when I access http://localhost:8080/liferay-portal it seems that the content is redirected to http://localhost:8080/web/guest and get the error page from Tomcat (The requested resource (/web/guest) is not available.).

    PS. I understand that this instructions you maded in Linux SO. In file portal-ext.properties I didn’t set the portal.ctx and liferay.home, I guess that this variables are optional, or, if not, give me an example on how to set this variable for windows OS.

    Reply
  7. mikeg says:
    September 23, 2009 at 7:28 am

    This article is great, I’ve been able to deploy a working liferay application following the instructions in this article. I agree with karthik – an article on deploying portlets and themes would be great.

    Reply
  8. trex says:
    November 3, 2009 at 8:25 am

    Kudos on a great writeup. Easy to read, easy to follow.

    My question goes to your statement on plug-ins and themes not being able to be installed automatically. I’ve been attempting to install plug-ins such as WOL with mixed success. I was wondering if you have any words of wisdom? Right now i can get the war(s) up and running, they just don’t appear to want to integrate with the liferay portal/database.

    Many thanks.

    Reply
  9. Suresh says:
    December 1, 2009 at 4:09 am

    Hi Steve,

    Great article! I got it working, but the problem I am having is that , when I deploy a portlet, it is not seen in either of the instances. The portlets deploy without an error, but when you go to add an application, you do not see the deployed portlets at all.

    Reply
  10. vychtrle says:
    February 12, 2010 at 8:26 pm

    I have an issue with multiple tomcat instances. I was building 5.3 from source and deployed it to tomcat. I left there only /webapp, /lib/ext, conf/server.xml, and modified /bin/startup.sh&shutdown.sh script for having different $CATALINA_BASE. I setup server.xml for connector to listen on different IP and changed hostname.

    /opt/jdk1.6.0_16/bin/java -Dnop Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Xms766m -Xmx1024m -XX:MaxPermSize=512m -Djava.endorsed.dirs=/opt/aaa/apache-tomcat-6.0.20/endorsed -classpath :/opt/aaa/apache-tomcat-6.0.20/bin/bootstrap.jar -Dcatalina.base=/opt/apache-tomcat-6.0.20 -Dcatalina.home=/opt/aaa/apache-tomcat-6.0.20 -Djava.io.tmpdir=/opt/apache-tomcat-6.0.20/temp org.apache.catalina.startup.Bootstrap start

    It boots up, listens on that IP and port, but doesn’t respond at all, it’s like the requests get lost and doesn’t even get logged.

    Reply
    • steveonjava says:
      February 12, 2010 at 11:22 pm

      Sounds like you got the basic Tomcat mult-instance steps down. Since setting up multiple instances of Tomcat on the same box is not the point of this article, you might want to refer to another resource like this: http://azeditech.com/tomcat/multiple-tomcat-instances.html

      Reply
  11. Andor Vierbergen says:
    September 2, 2010 at 7:35 am

    Hi Steve. Great article. There isn’t much (Liferay) information around on how to deploy the standalone war. I missed your comment about automatic deployment of the plugins/portlets/themes, etc. i got Liferay working, but had indeed the problem of automatic deployment. It took me a while to figure out why this doesn’t work in this setup. If the additional dependencies are loaded by Tomcat at startup from /lib/ext (add to common.loader in /conf/catalina.properties) everything works fine. If the additional dependencies are added to the liferay context in /WEB-INF/lib, automatic deployment and registration of plugins/portlets/themes fails. Perhaps it has something to do with class loaders etc?

    If you know how to solve this, it would be nice to hear. Otherwise, it would be nice how one could work around this by manually installing and registering the plugins/portlets/themes.

    Thanks for this article anyway. Helped a lot!

    With regards,

    Andor Vierbergen

    Reply
    • Alexander says:
      July 27, 2011 at 8:09 pm

      Hi, is possible that you explain how did you achieved “If the additional dependencies are loaded by Tomcat at startup from /lib/ext (add to common.loader in /conf/catalina.properties) everything works fine.”

      Would you add the catalina.properties setup and a detail about which jar do u have and where are they.

      Thanks in Advance
      Alexander

      Reply
  12. Andor Vierbergen says:
    September 2, 2010 at 7:40 am

    By the way, the steps in this article still work on:
    – Liferay 6.0.5
    – Tomcat 6.0.26
    – Java 1.6.0_21

    Reply
  13. Manoj says:
    September 7, 2010 at 3:51 pm

    Hi,
    how to change jvm memory size in tomcat shared hosting.
    that is adding -Xms128m -Xmx512m -XX:MaxPermSize=128m

    Thanks,
    Manoj

    Reply
    • steveonjava says:
      September 7, 2010 at 4:45 pm

      You will have to ask your ISP to change the settings globally since you are in a shared host. For my ISP they have a fairly high limit (almost 2GB of memory allocated), so I would ask for the sky…

      Reply
  14. Frans says:
    October 18, 2010 at 4:15 pm

    we use liferay since 4.x, and all our websites (20), including JUG Indonesia and JUG asia, using liferay. cool virtual host feature make one liferay multiple dotcom

    Reply
  15. Kostas Karkaletsis says:
    September 9, 2011 at 5:44 am

    I did all the steps but after starting I get this error
    16:36:42,865 INFO [PortalImpl:3829] Current URL /portal/el/ generates exception
    : /html/portal/layout/view/portlet.jsp(17,1) /html/portal/init.jsp(17,1) File “/
    html/common/init.jsp” not found

    Any idea on this?

    Reply
    • steveonjava says:
      September 11, 2011 at 12:36 am

      Did you try accessing that url directly yourself? You should be able to type in the url into your browser and it will either work (in which case the error message is bogus), or it will not (which might be a corrupt installation or a url mapping issue in your server setup).

      Reply

Leave a Reply

Click here to cancel reply.

Follow @steveonjava Follow @_nighthacking
Travel Map

Publications

  

Affiliations

Awards

2009/2011/2012 JavaOne Rock Star!

Disclaimer

Views and opinions expressed here are all my fault... complain to me, not my employer. :)
rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox