Thursday, October 28, 2010

Dependency Injection in PHP vs Java

How to do Dependency Injection in PHP vs Java.

Plain PHP:

$helper_sales = new HelperSales();

Magento proprietary SPI:

// no type information!
$helper_sales = Mage::helper('sales');

Java / CDI :

@Inject
private HelperSales helperSales;

Java / get bean from Spring context :

HelperSales helperSales = appCtx.getBean(HelperSales.class);

The Java examples apply to Scala as well, of course.

Still envy PHP?

Sunday, October 24, 2010

PrimeFaces supports Bean Validation (JSR-303) in JSF 2.0

I've found (at least) one thing PrimeFaces / JSF 2.0 does something better than Vaadin when it comes to RIA (Rich Internet Web Applications), and that is Bean Validation (JSR-303) support.

The following Java code:
@NotNull

@Size(min=1) private String surname;
will automatically become validated JSF components in your XHTML/VDL file.

Cool!

Displaying AJAX Tables in PHP vs Java EE: ZFDataGrid and PrimeFaces DataTable

While developing with PHP + Zend Framework + Doctrine I missed an easy way to display/edit data using a grid/table.

A very useful component I found is ZFDataGrid.

Here's a sample code of how to use ZFDataGrid:

    function simpleAction()

    {         //Zend_Config         $config = new Zend_Config_Ini('./application/grids/grid.ini', 'production');                 //Grid Initialization         $grid = Bvb_Grid::factory('Bvb_Grid_Deploy_Table', $config, 'id');                 //Setting grid source         $grid->setSource(new Bvb_Grid_Source_Zend_Table(new Bugs()));                 //CRUD Configuration         $form = new Bvb_Grid_Form();         $form->setAdd(true)->setEdit(true)->setDelete(true);         $grid->setForm($form);                 //Pass it to the view         $this->view->pages = $grid;         $this->render('index');     }
It looks pretty good too.

Check the ZFDataGrid Live Demo here.

However, working with data grids using JSF 2.0 and PrimeFaces felt much more natural and easier.

Here's a sample code using PrimeFaces' DataTable :

<h:form>

    <p:dataTable var="car" value="#{tableBean.lazyModel}" paginator="true" rows="10" lazy="true"
                 paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
                 rowsPerPageTemplate="5,10,15"
                 selection="#{tableBean.selectedCar}" selectionMode="single"
                 onRowSelectComplete="carDialog.show()" onRowSelectUpdate="display">
        <f:facet name="header">
            Displaying 100,000,000 Cars
        </f:facet>
        <p:column headerText="Model">
            <h:outputText value="#{car.model}" />
        </p:column>
        <p:column headerText="Year">
            <h:outputText value="#{car.year}" />
        </p:column>
        <p:column headerText="Manufacturer">
            <h:outputText value="#{car.manufacturer}" />
        </p:column>
        <p:column headerText="Color">
            <h:outputText value="#{car.color}" />
        </p:column>
    </p:dataTable>

    <p:dialog header="Car Detail" widgetVar="carDialog" resizable="false"
              width="200" showEffect="explode" hideEffect="explode">
        <h:panelGrid id="display" columns="2" cellpadding="4">
            <f:facet name="header">
                <p:graphicImage value="/images/cars/#{tableBean.selectedCar.manufacturer}.jpg"/>
            </f:facet>
            <h:outputText value="Model:" />
            <h:outputText value="#{tableBean.selectedCar.model}"/>

            <h:outputText value="Year:" />
            <h:outputText value="#{tableBean.selectedCar.year}"/>

            <h:outputText value="Manufacturer:" />
            <h:outputText value="#{tableBean.selectedCar.manufacturer}"/>

            <h:outputText value="Color:" />
            <h:outputText value="#{tableBean.selectedCar.color}"/>
        </h:panelGrid>
    </p:dialog>

</h:form>

The above code may look verbose, but it packs a lot of functionality and it's very easy and intuitive to customize.
When you click a row it displays a nice dialog with a picture. Furthermore, it's actually lazy loading 100,000,000 rows!! (yes, ONE HUNDRED MILLION ROWS)

Here's how it looks:

You can see for real the PrimeFaces DataTable Lazy-loading Live Demo here.

It's very easy to add lazy-loading support to DataTable:

        lazyModel = new LazyDataModel<Car>() {

/**
* Dummy implementation of loading a certain segment of data.
* In a real application, this method should load data from a datasource
*/
@Override
public List<Car> load(int first, int pageSize, String sortField, boolean sortOrder, Map<String,String> filters) {
logger.log(Level.INFO, "Loading the lazy car data between {0} and {1}", new Object[]{first, (first+pageSize)});

                //Sorting and Filtering information are not used for demo purposes just random dummy data is returned

List<Car> lazyCars = new ArrayList<Car>();
populateLazyRandomCars(lazyCars, pageSize);

return lazyCars;
}
};

        /**
         * In a real application, this number should be resolved by a projection query
         */
        lazyModel.setRowCount(100000000);

Not to disrespect PHP or ZFDataGrid in anyway (I still need to use them for some of my work), but the experience with JSF 2.0 and PrimeFaces wins hands down. I think it's more because of PrimeFaces than JSF 2.0, but they're such a powerful combo (compared to if you use PrimeFaces with JSF 1.2).

I do hope that PrimeFaces provide a utility class that implements LazyDataModel for a Hibernate/HQL or JPA/JPQL query, but for now I can live with the above.

Vaadin on Google App Engine part 1: Setting up the Development Environment

Vaadin is such a nice Java web RIA application framework for building desktop-like apps, built on top of GWT AJAX Library. Vaadin uses Java to programmatically create UI components and there's very minimal CSS / HTML involved, much less JavaScript.

In this article series I will share my experiences on developing a Vaadin web application and deploying it to Google App Engine hosting.

Prepare the Vaadin + Google Development Environment


First you need to prepare your development environment.

  1. Install Eclipse IDE 3.6SR1 (Helios) - Java EE edition
  2. Install Vaadin Eclipse Plugin
  3. Install Google Plugin for Eclipse
  4. Download the latest Google App Engine SDK . This step is optional because Google Plugin for Eclipse can also download GAE SDK and GWT SDK for you.

Useful Reading

Vaadin on Google App Engine part 1: Setting up the Development Environment

Vaadin is such a nice Java web RIA application framework for building desktop-like apps, built on top of GWT AJAX Library. Vaadin uses Java to programmatically create UI components and there's very minimal CSS / HTML involved, much less JavaScript.

In this article series I will share my experiences on developing a Vaadin web application and deploying it to Google App Engine hosting.

Prepare Vaadin + Google App Engine Development Environment


First you need to prepare your development environment.

  1. Install Eclipse IDE 3.6SR1 (Helios) - Java EE edition
  2. Install Vaadin Eclipse Plugin
  3. Install Google Plugin for Eclipse
  4. Download the latest Google App Engine SDK . This step is optional because Google Plugin for Eclipse can also download GAE SDK and GWT SDK for you.

Useful Reading

Vaadin on Google App Engine part 2: Creating the Web Application Project

To create a Vaadin web application on Google App Engine, in Eclipse IDE click File > New > Project... and create a new Vaadin project.

Make sure you choose Google App Engine as the Deployment configuration.

Then enable Google App Engine nature in your project:

  1. Right click your project > Properties...
  2. Go to Google > App Engine
  3. Check the Use Google App Engine checkbox
  4. Pick the Google App Engine SDK that you use or click Configure SDKs... if necessary

To ensure that JDO enhancement by DataNucleus access platform works correctly, do the following workaround:
  1. Right click your project > Properties...
  2. Go to Java Build Path
  3. Remove Web App Libraries
  4. Click Add JARs..., and select the war/WEB-INF/lib/vaadin-x.x.x.jar
Now your Vaadin application should run fine. You can also start adding JDO entities with proper DataNucleus JDO code enhancement.

Eclipse Helios In Action: Modeling with Acceleo and Xtext

The Eclipse Modeling Project is one of the most active projects within the Eclipse community. Ed Merks will give a quick overview of the Modeling projects in Eclipse IDE 3.6 Helios. Then Cedric Brun will demo Acceleo and Sebastian Zarnekow will show Xtext.

This presentation was recorded as part of the Helios In Action virtual conference: eclipse.org/​helios/​heliosinaction.php.

Presented by Ed Merks, Cedric Brun of Obeo and Sebastian Zarnekow of itemis

See the webinar recording video here: Helios In Action: Modeling

Eclipse IDE 3.6 Helios In Action: EMF on the Web

The Eclipse Modeling Framework (EMF) has long provided a code generation facility capable of emitting everything needed to get started with building a complete application for EMF-based domain models. It includes a GUI from which options can be specified and code generators can be invoked, to produce a model API, edit support, unit tests and a sample editor.

With the Helios release of Eclipse, this facility moves beyond the boundaries of the Eclipse platform, and desktop applications in general, by adding support for the Rich Ajax Platform (RAP) and Google Web Toolkit (GWT). This session will demonstrate EMF's support for these application runtime platforms and highlight differences in the code generated for each.

This presentation was recorded as part of the Helios In Action virtual conference: eclipse.org/​helios/​heliosinaction.php.

Presented by Kenn Hussey, Cloudsmith

See the webinar recording video here: Helios In Action: EMF on the Web

Saturday, October 23, 2010

Failed trying to bake Spring into Vaadin + GAE + JDO

I'm doing web application development using Vaadin, Google App Engine, JDO / DataNucleus, and... Spring Framework.

Spring Framework actually works fine, except for the JDO part. And I'm not touching transaction management yet!

When getting PersistenceManagerFactory programmatically, the app works great.

public class PMF {

private static final PersistenceManagerFactory pmfInstance = JDOHelper
.getPersistenceManagerFactory("transactions-optional");

private PMF() {
}

public static PersistenceManagerFactory get() {
return pmfInstance;
}
}

Usage:

home.addComponent(new Button("View", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Collection<Organization> orgs = (Collection<Organization>) pm.newQuery(Organization.class).execute();
mainWindow.showNotification("You have " + orgs.size());
} finally {
pm.close();
}
}
}));

However, when using Spring Framework, it... sort of... doesn't work. I'll explain the "sort of" part later.

Here's part of my applicationContext.xml :

<bean id="persistenceManagerFactory"
class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean">
<property name="persistenceManagerFactoryName" value="transactions-optional" />
</bean>

And using it:

@Autowired
private PersistenceManagerFactory pmf;
...
home.addComponent(new Button("View", new Button.ClickListener() {
@Override
public void buttonClick(ClickEvent event) {
PersistenceManager pm = pmf.getPersistenceManager();
try {
Collection<Organization> orgs = (Collection<Organization>) pm.newQuery(Organization.class).execute();
mainWindow.showNotification("You have " + orgs.size());
} finally {
pm.close();
}
}
}));

It's a simple change.

The app loads, and doing database operations on the Vaadin Application.init() works fine. However, trying to do database operations on a button click handler for example, throws the following exception:

com.vaadin.event.ListenerMethod$MethodException
Cause: javax.jdo.JDOFatalUserException: No available StoreManager found for the datastore URL key "". Please make sure you have all relevant plugins in the CLASSPATH (e.g datanucleus-rdbms?, datanucleus-db4o?), and consider setting the persistence property "datanucleus.storeManagerType" to the type of store you are using e.g rdbms, db4o
NestedThrowables:
org.datanucleus.exceptions.NucleusUserException: No available StoreManager found for the datastore URL key "". Please make sure you have all relevant plugins in the CLASSPATH (e.g datanucleus-rdbms?, datanucleus-db4o?), and consider setting the persistence property "datanucleus.storeManagerType" to the type of store you are using e.g rdbms, db4o
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:507)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:161)
at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1154)
at com.vaadin.ui.Button.fireClick(Button.java:371)
at com.vaadin.ui.Button.changeVariables(Button.java:193)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1094)
at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:590)
at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:266)
at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:476)
at com.vaadin.terminal.gwt.server.GAEApplicationServlet.service(GAEApplicationServlet.java:242)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: javax.jdo.JDOFatalUserException: No available StoreManager found for the datastore URL key "". Please make sure you have all relevant plugins in the CLASSPATH (e.g datanucleus-rdbms?, datanucleus-db4o?), and consider setting the persistence property "datanucleus.storeManagerType" to the type of store you are using e.g rdbms, db4o
NestedThrowables:
org.datanucleus.exceptions.NucleusUserException: No available StoreManager found for the datastore URL key "". Please make sure you have all relevant plugins in the CLASSPATH (e.g datanucleus-rdbms?, datanucleus-db4o?), and consider setting the persistence property "datanucleus.storeManagerType" to the type of store you are using e.g rdbms, db4o
at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:354)
at org.datanucleus.jdo.JDOPersistenceManagerFactory.freezeConfiguration(JDOPersistenceManagerFactory.java:544)
at org.datanucleus.jdo.JDOPersistenceManagerFactory.getPersistenceManager(JDOPersistenceManagerFactory.java:576)
at org.datanucleus.jdo.JDOPersistenceManagerFactory.getPersistenceManager(JDOPersistenceManagerFactory.java:557)
at com.abispulsa.bisnis.mobile.VaadinApp$1.buttonClick(VaadinApp.java:62)
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 com.google.appengine.tools.development.agent.runtime.Runtime.invoke(Runtime.java:100)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:487)
... 35 more
Caused by: org.datanucleus.exceptions.NucleusUserException: No available StoreManager found for the datastore URL key "". Please make sure you have all relevant plugins in the CLASSPATH (e.g datanucleus-rdbms?, datanucleus-db4o?), and consider setting the persistence property "datanucleus.storeManagerType" to the type of store you are using e.g rdbms, db4o
at org.datanucleus.store.FederationManager.initialiseStoreManager(FederationManager.java:197)
at org.datanucleus.store.FederationManager.<init>(FederationManager.java:70)
at org.datanucleus.ObjectManagerFactoryImpl.initialiseStoreManager(ObjectManagerFactoryImpl.java:153)
at org.datanucleus.jdo.JDOPersistenceManagerFactory.freezeConfiguration(JDOPersistenceManagerFactory.java:526)
... 44 more

I'm really not sure what I did wrong... I also tried the alternative way of getting PersistenceManagerFactory per GAE's guide:

<bean id="persistenceManagerFactory" class="javax.jdo.JDOHelper" factory-method="getPersistenceManagerFactory">
<constructor-arg value="transactions-optional" />
</bean>

Result is exactly the same. I tried adding PersistenceManagerFactoryProxy and still the same error.

I tried adding a TransactionManager :

<bean id="persistenceManagerFactory"
class="org.springframework.orm.jdo.LocalPersistenceManagerFactoryBean" autowire-candidate="false">
<property name="persistenceManagerFactoryName" value="transactions-optional" />
</bean>

<bean id="persistenceManagerFactoryProxy"
class="org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy">
<property name="targetPersistenceManagerFactory" ref="persistenceManagerFactory" />
<property name="allowCreate" value="true" />
</bean>

<bean id="transactionManager" class="org.springframework.orm.jdo.JdoTransactionManager">
<property name="persistenceManagerFactory" ref="persistenceManagerFactory" />
</bean>

still doesn't work.

I tried making the Spring PersistenceManagerFactoryProxy scope="session" and I get an exception saying it is not serializable (a common problem in Google App Engine development):

Oct 23, 2010 5:48:45 PM com.vaadin.terminal.gwt.server.GAEApplicationServlet service
SEVERE: NotSerializableException: java.io.NotSerializableException: org.springframework.orm.jdo.TransactionAwarePersistenceManagerFactoryProxy$PersistenceManagerFactoryInvocationHandler
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1164)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at java.util.HashMap.writeObject(HashMap.java:1000)
at sun.reflect.GeneratedMethodAccessor7.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1518)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1483)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
at com.vaadin.terminal.gwt.server.GAEApplicationServlet.service(GAEApplicationServlet.java:248)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
at org.mortbay.jetty.Server.handle(Server.java:326)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)

Right now I'm stuck with Spring Framework and JDO.

There are several alternatives for me now:
  1. Leave JDO alone, use Spring for other parts of application
  2. Try another dependency injection framework, like Guice or Weld/CDI
  3. Keep banging my head...? :P

Friday, October 22, 2010

Session Expired error in Vaadin and Google App Engine

When developing a Vaadin RIA web application on Google App Engine and you get the following error when clicking a button or any UI action:

Session Expired
 
Take note of any unsaved data, and click here to continue.

90% of the time it means your program throws an Exception.

So check the Console for exceptions and fix it.

Configuring Vaadin, GAE, and DataNucleus JDO using Vaadin Eclipse Plugin and Google Eclipse Plugin

The following combination:
  • Vaadin 6.4.6
  • GAE SDK 1.3.8
  • DataNucleus JDO 1.1.5 for Google App Engine (adapter version: 1.0.7)
  • Vaadin Eclipse Plugin 1.2.1
  • Google Plugin for Eclipse 1.3.3
  • Eclipse Helios 3.6SR1
When building a Google App Engine project and your encounter the following error message:

Encountered a problem: Unexpected exception
Please see the logs [/tmp/enhance7599385286098074928.log] for further information.

that log file contains:

java.lang.RuntimeException: Unexpected exception
at com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:59)
at com.google.appengine.tools.enhancer.Enhance.<init>(Enhance.java:60)
at com.google.appengine.tools.enhancer.Enhance.main(Enhance.java:41)
Caused by: java.lang.reflect.InvocationTargetException
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 com.google.appengine.tools.enhancer.Enhancer.execute(Enhancer.java:57)
... 2 more
Caused by: org.datanucleus.exceptions.NucleusException: Plugin (Bundle) "org.datanucleus.store.appengine" is already registered. Ensure you dont have multiple JAR versions of the same plugin in the classpath. The URL "file:/home/ceefour/Vendor/appengine-java-sdk-1.3.8/lib/user/orm/datanucleus-appengine-1.0.7.final.jar" is already registered, and you are trying to register an identical plugin located at URL "file:/home/ceefour/project/AbisPulsa/abispulsabisnis/war/WEB-INF/lib/datanucleus-appengine-1.0.7.final.jar."
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:434)
at org.datanucleus.plugin.NonManagedPluginRegistry.registerBundle(NonManagedPluginRegistry.java:340)
at org.datanucleus.plugin.NonManagedPluginRegistry.registerExtensions(NonManagedPluginRegistry.java:222)
at org.datanucleus.plugin.NonManagedPluginRegistry.registerExtensionPoints(NonManagedPluginRegistry.java:153)
at org.datanucleus.plugin.PluginManager.registerExtensionPoints(PluginManager.java:82)
at org.datanucleus.OMFContext.<init>(OMFContext.java:160)
at org.datanucleus.enhancer.DataNucleusEnhancer.<init>(DataNucleusEnhancer.java:172)
at org.datanucleus.enhancer.DataNucleusEnhancer.<init>(DataNucleusEnhancer.java:150)
at org.datanucleus.enhancer.DataNucleusEnhancer.main(DataNucleusEnhancer.java:1157)
... 7 more

* * * * * * * *

The Solution to this problem:
  1. Go to Project > Properties > Java Build Path
  2. Remove Web App Libraries
  3. Click Add JARs... , and add your Vaadin JAR from your project's war/WEB-INF/lib

* * * * * * * *

The reason is because Google Plugin for Eclipse copies DataNucleus libraries to war/WEB-INF/lib (which is "Web App Libraries") and itself (the Google App Engine SDK) already contains DataNucleus libraries.

The problem is in how GAE plugin interacts with the standard Eclipse Web Tools Platform (WTP). The Google plugin is designed to work primarily with its own non-WTP projects, and apparently does not handle WTP projects correctly. There is minimal documentation for using the Google plugin in existing projects (such as WTP), but it does not address this issue.

In summary, considering this a Google plugin WTP incompatibility, not a Vaadin plugin specific problem.

For more info see:

Saturday, October 16, 2010

Vaadin application not refreshing in Eclipse internal browser - and how to fix it

Yesterday I was frustrated because at some point, after making a change in my Vaadin-Scala RIA web application, the application won't refresh at all!

I tried:

  • refreshing the browser (tens of times!)
  • appending a query string at the end of URL
  • republishing the app (whether automatically, incrementally, Full Republish)
  • restarting the server
  • running the server in Debug mode... nothing works!

Nothing works.

I almost suspected it's because of Scala, because Scala IDE Plugin for Eclipse 3.6 Helios is still not in final version. I could have just used Java but...

There's no compilation error whatsoever. I didn't even use Maven (yet). So what could go wrong?

Then I opened the application using Google Chrome and it shows the latest version of my application!

It turns out that something is wrong with Eclipse XUL Browser (internal browser) and caching.

So the fix/workaround turned out to be very simple: don't use Eclipse XUL Browser (internal browser)... use a real external browser (Firefox, Google Chrome, Opera, whatever as long as it's not internal browser)!

Wednesday, October 13, 2010

Fixing org.apache.jasper.JasperException: PWC6180: Unable to initialize TldScanner Error on GlassFish 3.0.1

If you get the following error when running a Java EE 6 / JSF 2.0 web application in GlassFish 3.0.1 :

Oct 14, 2010 1:05:26 AM org.apache.catalina.core.StandardContext callServletContainerInitializers
SEVERE: PWC1420: Error invoking ServletContainerInitializer org.apache.jasper.runtime.TldScanner
org.apache.jasper.JasperException: PWC6180: Unable to initialize TldScanner
at org.apache.jasper.runtime.TldScanner.scanTlds(TldScanner.java:287)
at org.apache.jasper.runtime.TldScanner.onStartup(TldScanner.java:228)
at org.apache.catalina.core.StandardContext.callServletContainerInitializers(StandardContext.java:5352)
at com.sun.enterprise.web.WebModule.callServletContainerInitializers(WebModule.java:550)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5263)
at com.sun.enterprise.web.WebModule.start(WebModule.java:499)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:928)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:912)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:694)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1947)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1619)
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:90)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:241)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:236)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:339)
at org.glassfish.kernel.embedded.EmbeddedDeployerImpl.deploy(EmbeddedDeployerImpl.java:214)
at org.glassfish.kernel.embedded.EmbeddedDeployerImpl.deploy(EmbeddedDeployerImpl.java:144)
at org.glassfish.maven.RunMojo.execute(RunMojo.java:98)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:107)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:195)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:140)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:314)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:151)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:445)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:168)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:132)
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.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:290)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:230)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:409)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Caused by: java.lang.IllegalArgumentException: javax.servlet.ServletException: com.sun.enterprise.container.common.spi.util.InjectionException: Error creating managed object for class com.sun.appserv.web.taglibs.cache.CacheContextListener
at org.apache.catalina.core.StandardContext.addListener(StandardContext.java:2659)
at org.apache.catalina.core.StandardContext.addListener(StandardContext.java:2642)
at org.apache.catalina.core.ApplicationContext.addListener(ApplicationContext.java:1270)
at org.apache.catalina.core.ApplicationContextFacade.addListener(ApplicationContextFacade.java:665)
at org.apache.jasper.runtime.TldScanner.addListener(TldScanner.java:435)
at org.apache.jasper.runtime.TldScanner.scanJar(TldScanner.java:420)
at org.apache.jasper.runtime.TldScanner.scanJars(TldScanner.java:633)
at org.apache.jasper.runtime.TldScanner.scanTlds(TldScanner.java:282)
... 39 more

The solution is to update the jsp-impl.jar library file since GlassFish 3.0.1 used an older and buggy one.

Download the newest jsp-impl.jar from http://download.java.net/maven/2/org/glassfish/web/jsp-impl/
(currently the newest version is 2.2.2-b03)

Overwrite the file in ${GLASSFISH_HOME}/glassfish/modules/jsp-impl.jar with the new jsp-impl.jar (rename the file to omit the version number).

Now your Java EE applications should run just fine. I also run a mixed Java EE/Scala web application and it runs fine with the new jsp-impl.jar.

Sunday, October 10, 2010

Installing M2Eclipse from "hidden" Archived Update Site

The latest M2Eclipse Maven Plugin for Eclipse IDE versions actually has archived update site files for offline installation.

However it is currently not mentioned in M2Eclipse Installation page.

You can download the recent archived update sites here:
http://repository.sonatype.org/content/repositories/eclipse/org/maven/ide/eclipse/org.maven.ide.eclipse.site

For example, this is the latest update site as of this writing:
http://repository.sonatype.org/content/repositories/eclipse/org/maven/ide/eclipse/org.maven.ide.eclipse.site/0.10.2.20100623-1649/org.maven.ide.eclipse.site-0.10.2.20100623-1649-site.zip

To maintainers of M2Eclipse, *PLEASE* update this Installation page:
http://m2eclipse.sonatype.org/installing-m2eclipse.html

and mention the existence of the archives of update site at the following URL:
http://repository.sonatype.org/content/repositories/eclipse/org/maven/ide/eclipse/org.maven.ide.eclipse.site

I found the archived update site location by following MNGECLIPSE-858 issue history here plus some common sense. ;-)

Friday, October 8, 2010

Apache Maven 3.0 Released [New Version Announcement]

The Maven team is pleased to announce the release of Apache Maven 3.0.

Maven is a project comprehension and build tool, designed to simplify
the process of maintaining a healthy development lifecycle for your
project. You can read more here:

http://maven.apache.org/

Downloads of source and binary distributions are listed in our download
section:

http://maven.apache.org/download.html

A major goal of Maven 3.0 is to be compatible, to the extent possible,
with existing plugins and projects designed for Maven 2.x. Users
interested in upgrading to this new major release should have a glance
at the compatibility notes for known differences between Maven 3.0 and
Maven 2.x:

http://cwiki.apache.org/MAVEN/maven-3x-compatibility-notes.html

If you encounter unexpected problems while using Maven 3.0, please feel
free to contact us via the Maven developer list:

http://maven.apache.org/mail-lists.html

Last but not least, the Maven team would like to thank all the users
that tested the various alphas/betas/RCs and provided valuable feedback
that helped us to eventually release a solid Maven 3.0!

Release Notes - Maven 2 & 3 - Version 3.0 (since 3.0-beta-3 only)

** Bug
* [MNG-4592] - Snapshot artifacts that could not be downloaded due
to communication problems are "blacklisted" for a day by default.
* [MNG-4751] - Snapshot version not resolved for version range
* [MNG-4785] - NPE in dependency resolution code for TC plugin
* [MNG-4786] - [regression] Ant-based mojo using
maven-script-ant:2.1.0+ cause NPE
* [MNG-4788] - [regression] Appassembler Maven Plugin doesn't work
like as it should
* [MNG-4789] - [regression] Difference in compile scope dependency
resolution
* [MNG-4791] - [regression] POM artifacts passed into
MavenProjectBuilder.buildFromRepository() are no longer resolved
* [MNG-4793] - Unable to obtain archiver for extension 'zip'
* [MNG-4794] -
'org.apache.maven.plugins:maven-install-plugin:2.3.1'. A required class
is missing: org.codehaus.plexus.digest.Digester
* [MNG-4795] - [regression] Dependencies in forked reactor projects
are not resolved when aggregator bound to lifecycle forks
* [MNG-4800] - Conflict resolution does not pick sub tree of
nearest dependency if farther conflicting dependency has wider scope
* [MNG-4810] - Maven cannot build if loaded in a classloader that
is not backed by a real JAR file / classpath
* [MNG-4811] - Custom Maven Plugin regression in Maven 3.x, custom
ComponentConfigurator causes infinite loop
* [MNG-4814] - Eary dependency resolution attempts for reactor
projects prevent their later resolution from the reactor
* [MNG-4818] - NPE in legacy.DefaultWagonManager.getArtifact
* [MNG-4829] - [regression] Checksum failures aren't logged
* [MNG-4832] - Maven 3 Regression: Missing constructor of
org.codehaus.plexus.component.configurator.converters.special.ClassRealmConverter
* [MNG-4834] - [regression] MavenProject.getParent() ignores
configured repositories
* [MNG-4836] - Incorrect recursive expression cycle errors (update
plexus-interpolation)
* [MNG-4837] - Interpolation error due to cyclic expression for one
of the POM coordinates gets needlessly repeated
* [MNG-4842] - [regression] Repositories discovered in dependency
POMs override repositories configured for original resolution request of POM
* [MNG-4845] - [regression] MavenProject.getDependencyArtifact()
returns artifacts without version for dependency with version range

** Improvement
* [MNG-4452] - Metadata for snapshots should include classifier
* [MNG-4787] - Allow class realm manager delegates to alter public
part of Maven core realm
* [MNG-4815] - (3.0-RC1) Maven Java API does not give nice error
messages when improperly configured
* [MNG-4824] - multiple failures need additional whitespace
* [MNG-4825] - Relative path errors could be more explicit

** New Feature
* [MNG-4484] - Create a Maven API for component configuration

** Task
* [MNG-4805] - Update default plugin versions used for built-in
lifecycle mappings
* [MNG-4807] - Extend core artifact filter to exclude relocated
Guice-based Plexus shim

** Wish
* [MNG-4796] - add a warning when profiles.xml is used (Maven 2) or
detected (Maven 3)

Enjoy,


-The Maven team

Relational DBMS vs Object-oriented DBMS vs Document-oriented databases issue is moot when you're already using multiple data stores!

The issue of:

1. Relational databases (RDBMS) e.g. MySQL, PostgreSQL, SQLite, JavaDB, HSQLDB... versus
2. Object-Oriented databases (OODBMS) e.g. db4o... versus
3. Document-oriented databases e.g. MongoDB, Apache CouchDB...

...is probably because many developers (including me! :) are not aware that the application is already using multiple data stores at once.

Note: Practically all data stores, except OODBMS, will require some form of roundtrip serialization, object-mapping and code generation to be conveniently usable inside an application, accessible not only via framework/library API but also via domain model objects and classes.

By the way even if you use an OODBMS, if you use features that require specific language support (e.g. Weaving traits and behaviors, like soft deletes, timestampable, nested sets) and the language (e.g. PHP, Java) doesn't support it, you'll still need to do either code generation, manual coding, or be content with dynamic proxying (say goodbye to IDE code hints!)

Why pick just one data store and debate?

A few I have in mind right now is:

1. Key-value stores.
The application INI configuration file.
Cache storage, be it file-backed, memcached-backed, or even RDBMS-backed! (you're just abstracting/implementing a key-value store on top of a relational schema).
Translation/localization data is sometimes also stored using this store.
Web application Session data also uses key-value (though it does automatic de/serialization).

2. Hierarchical data store / Object store.
XML file.
A hierarchy of folders, subfolders, and files.
In the case of Zend Frameworks's Zend_Config, also INI files.
JSON file.
YAML file.
CSS file (surprising, eh? Though it's only two levels deep.)
I think there's no such thing as an "object store". What exists is a data store that acts like an object repository, that does automatic de/serialization of objects, that stores its data in a hierarchical store or content/document store or hybrid.
How an object is serialized/its serialization representation (i.e. "should a GeoPoint instance be embedded or linked?") should be specifiable through some form of metadata/configuration/annotations.
The object graph, by itself, does not contain sufficient information to be managed as a data store.

3. Content/Document store.
A content store doesn't always restrict a type to a schema. It allows arbitrary properties to be attached to a content node.
Some content stores also allow nesting (hierarchical content stores).
The filesystem (fixed standard schema), but some filesystems support additional metadata.
The node API in Drupal (implemented on top of RDBMS).
The EAV tables in Magento (implemented on top of RDBMS).
Natively: the JCR (Java Content Repository) in Alfresco & Jackrabbit (Java), MongoDB, Apache CouchDB, Persevere.

4. Binary/BLOB store.
It's basically a key-value store with support for huge values and block/partial access.
The filesystem.
S3.

5. Structured markup.
HTML. Wiki format. Markdown. Textile.
All fits in one string.

6. Full text index store.
Apache Lucene.
Zend_Lucene.

7. Search store.
Apache Solr.
The search/faceted navigation index in Magento (built on top of RDBMS).

Did I miss something?