Broadleaf Commerce deployed on Cloud Foundry
I have been working a lot lately with Broadleaf Commerce and wondered what it would take to deploy it on VMware's Cloud Foundry . There are already a number of blogs and sources of documentation out there describing the simplicity and steps to deploy a Java / Spring web application to Cloud Foundry. However, there are a few key considerations with Broadleaf that I wanted to test and talk about. And besides, I wanted to try it all out for myself.
First, a little background...
Broadleaf, in my opinion, is the best enterprise class, open source eCommerce framework currently available. It is built in Java on top of proven frameworks such as The Spring Framework and Hibernate , among other things. Broadleaf Commerce provides a set of jar files, about 130 database tables, a domain model, a DAO layer, business services, a workflow engine, and an admin console right out of the box. But Broadleaf Commerce is a framework rather than a product, meaning that you can use it and extend it to build your own eCommerce application. It does not dictate your UI or user experience in any way. Rather it leaves it up to the user of the framework to develop this part of the application using Broadleaf Commerce as the back-end eCommerce engine. It is completely extensible, and allows you to completely customize and override the data model and functionality as required. More on that in a minute.
VMware's Cloud Foundry is a new Platform as a Service, or PaaS, for deploying and running web applications in the cloud. It is one of the developments that came out of VMware's acquisition of SpringSource. It provides a simple approach for deploying applications without needing to think too much about infrastructure or scalability. In a nutshell, Cloud Foundry is an open source PaaS that wraps and abstracts the complexity of networking, software installation, configuration, security, deployment, and scaling of JVM-based web applications such as Java Spring applications, Groovy/Grails, Ruby, Scala, etc. It provides tools for deploying and managing your cloud instance in the form of a command line interface, and the SpringSource Tool Suite (STS). Cloud Foundry provides a number of data and messaging services out of the box, including MySQL, PostgreSQL, MongoDB, RabbitMQ, and Redis. Cloud Foundry is open source in the sense that the source is freely available. So technically, you should be able to run a Cloud Foundry VM on any number of cloud providers such as Amazon EC2 or Rackspace Cloud. But Cloud Foundry is making it simple to deploy an application to CloudFoundry.com without too much setup. Cloud Foundry also provides what they call Micro Cloud Foundry, a small instance of the Cloud Foundry platform that you can run and interact with locally using VMware Player, Workstation, or Fusion.
I should note that Cloud Foundry services are still in beta at this point and pricing has not been released yet.
As I mentioned, there is quite a bit of good documentation out there about deploying a Java / Spring web application to Cloud Foundry. However, most of them use the typical "Hello World" example, that avoids some of the more complicated concerns.
Broadleaf Commerce provides a demo application on Github at https://github.com/BroadleafCommerce/BroadleafCommerceDemoSite . The demo application represents an example of how one might use the Broadleaf Commerce Framework to build their own application. When the source is downloaded, it allows you to build and run the demo application directly from an IDE or command line. The resulting war file is about 72MB, a much larger war than most Hello World applications.
What's involved in building the Broadleaf demo? Not much more than downloading and importing the source as a Maven project, building it, and running an Ant script to start up a local HSQLDB and Jetty servlet container. As I mentioned, Broadleaf Commerce is a framework , and provides a set of jars and default configurations, including Spring and Hibernate configurations. It also provides a set of out-of-the-box JPA entities that, of course, map to standard database tables. So if the jars contain Spring application context files, persistence.xml files, and compiled classes, how do you customize it? That's part of the magic of Broadleaf. It uses a custom application context called MergeApplicationContext to merge and override configurations and bean definitions such as data sources and even things like business services. As long as you use the same Spring bean ids and reference an implementation of the same interface you can override any standard or default component of Broadleaf Commerce. The MergeApplicationContext essentially "overlays" your bean definition on the default Broadleaf configuration and overrides what Broadleaf provides out of the box with what you define. Pretty cool, huh?
This application context merge behavior is well defined and well understood in servlet containers such as Tomcat, and in application servers such as Glassfish, JBoss, WebLogic, and WebSphere. However, when deploying to Cloud Foundry, you don't choose a servlet container. Incidentally, it's Tomcat under the covers, but you don't really need to understand where / how the application is deployed. That's part of the appeal of CloudFoundry. Since there are a number of abstractions that Cloud Foundry prescribes (e.g. all applications, whether Spring, Ruby, or other are abstracted into a "Droplet" and treated the same way for at least part of the deployment process), I wondered if deploying to Cloud Foundry would interfere in some way with the unique application context merge process (since Broadleaf "hijacks" the Spring lifecycle to accomplish the merge).
Broadleaf Commerce also has a nice, sophisticated environment variable injection mechanism for replacing properties in the Spring application context, depending on the environment. This is similar to what Spring will be providing with Spring Profiles . Again, I wanted to ensure that this mechanism worked when deploying to Cloud Foundry.
Again, there are a number of great blogs on deploying a Spring application to Cloud Foundry. I am not going to reiterate these steps and configurations. However, with respect to the Broadleaf Commerce demo, I do want to summarize the steps with a few additional considerations.
- Download Broadleaf Commerce demo code, a fictitious coffee storefront, from Github
- Open the project in your favorite IDE (I used IntelliJ)
- Add the Cloud Foundry dependency to the pom file
- Modify the application context to use a special CloudFoundry data source configuration. In particular, change the existing datasource configuration to use <cloud:data-source id="webDS"/> . The cloud namespace is new and has to be added to the top of the application context configuration file.
- Modify the JPA Persistence Unit configuration (a.k.a. Hibernate) to use a MySQL dialect (instead of the demo default HSQLDB)
- Build the war file (Maven package command)
- Deploy the war to CloudFoundry
Well, I can say that I was definitely able to deploy the Broadleaf demo application to Cloud Foundry. I was able to deploy both to a Micro instance running locally and to the hosted CloudFoundry.com site. I was a bit surprised how little I had to change and how easy it ended up being. I had a few challenges that were difficult to troubleshoot. Of course I made some of my own silly mistakes, like forgetting to change the Hibernate dialect. I also found, by looking at the logs after a deployment failure, that I needed 1G of memory for this application, instead of the 512M that is the default. But when I got past my own configuration errors and everything seemed to be working properly, I got an error from the vmc client that said, "Error: Application 'broadleafdemo's state is undetermined, not enough information available" . There were no errors in the logs, and I'm still not entirely sure what caused this. I checked the state of the application and it was not running. I deleted the application and tried again. I tweaked some settings, consulted Google, changed from MySQL to PostgreSQL and back again. And I continued to get the same result. Finally, I deployed it, got the same dubious message, and walked away from it. A few minutes later I came back and it was working.
My guess is that it had to do with the size and complexity of the application. At 71MB it took a little longer to upload (which is typical of a Spring-based web application where the "app server" is inside the application rather than vice versa as is the case with a Java EE or EJB style of application). The startup process takes about a minute because of the number of Spring beans and merging of contexts. In addition this particular application is configured to allow Hibernate to build the database tables on startup. Also, since this is a demo application, there is an import.sql file in the application that Hibernate uses to seed the database.
Since there were no errors in the logs and patience solved the problem, I can only guess that there was some sort of timeout waiting for the application to start. Of course, this was confusing. But once I got past it everything worked like a charm and I was able to browse the catalog, add to cart, and do all of the things you would expect on an eCommerce demo site.
As for the things I wanted to verify, Cloud Foundry did not interfere with Broadleaf's unique application context merge process. Cloud Foundry APIs also allow you to specify environment variables. These can be used by Broadleaf Commerce to determine the appropriate property value replacements at startup.
Broadleaf Commerce, even though it's open source, is a formidable player in the enterprise eCommerce space. My understanding is that it is being used by some large online retailers including The Container Store, Pep Boys, Ganz (Webkins), Waste Management, and likely many others that I'm not aware of. In order to use the full suite of Broadleaf Commerce features in the cloud, especially on Cloud Foundry, some additional changes will be required. For example, Broadleaf uses JMS by default for asynchronous processing. Of course this is highly configurable. Using Broadleaf's merge functionality and Spring AMQP, overriding this behavior to use RabbitMQ would be quite easy. Also, Broadleaf Commerce is designed with PCI compliance in mind. However, the default functionality is reserved for a dedicated data center. In order to maintain security and compliance with PCI rules in the cloud, it would be best to avoid accepting payment information directly and use a service such as PayPal, Blue Pay, or others that allow you to redirect users to those services for payment processing. I have seen this approach used with Broadleaf Commerce and it works very well.
Cloud Foundry is still in beta, but is definitely on the right track as far as providing a simple, scalable, application platform for deploying and running an eCommerce storefront or any type of web application that runs in the Java Runtime Environment. The Broadleaf demo is a relatively large and complex application and deploying it to Cloud Foundry was surprisingly straight forward, requiring few changes. I would expect that Cloud Foundry will continue to improve its error handling and messaging to the client. I also expect that more back-end services will be added over time, increasing the potential level of sophistication of applications hosted on Cloud Foundry. One concern I have at this point is the scalability of the back-end services. Scaling the application tier is as simple as issuing a command. Back end services such as PostgreSQL and MySQL are not scaled so easily. Again, I would imagine that this will be addressed by the folks at Cloud Foundry in time.
In the end, deploying Broadleaf Commerce on Cloud Foundry was quite easy and as Cloud Foundry matures the two of them together look to provide a very feasible eCommerce platform.