SyntaxHighlighter

Thursday, March 13, 2014

CloudFoundry and a "normal" WAR - How to bind to a datasource on CloudFoundry

CloudFoundry and a "normal" WAR - How to bind to a datasource on CloudFoundry

so here's an interesting one; really want to use "cloud" and i have existing non-Spring WAR.  how can we bind to a datasource in a "flexible" way that doesn't require too much coding or rebuilding as a Spring App?

1. import a package from Spring (it looks like we're adding Spring, but there's really no influence, just one class)

 
  
   org.springframework.maven.milestone
   Spring Maven Milestone Repository
   http://repo.spring.io/milestone
  
 


  
   org.springframework.cloud
   cloudfoundry-connector
   0.9.5
  
  
   org.springframework.cloud
   spring-service-connector
   0.9.5
  
2. provide a way to bind to a CloudFoundry datasource

package io.pivotal.poc.simple.service;

import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cloud.CloudException;
import org.springframework.cloud.config.java.AbstractCloudConfig;

public class CloudConfiguration extends AbstractCloudConfig {

 private static final Logger logger = Logger.getLogger(CloudConfiguration.class);
 
 public CloudConfiguration() {
  BeanFactory factory = new DefaultListableBeanFactory();
  try {
   this.setBeanFactory(factory);
  }
  catch (CloudException e) {
   logger.warn("no cloud",e);//TODO clean up message
  }
 }
 
 public DataSource inventoryDataSource() {
  ServiceConnectionFactory connectionFactory = connectionFactory();
  if (connectionFactory != null) {
   return new ServiceConnectionFactory().dataSource("twitter-pgsql");//TODO clean up hard coding
  }//end if
  return null;
 }
 
}

3. provide the datasource as a servlet context attribute

package io.pivotal.poc.simple.listener;

import io.pivotal.poc.simple.service.CloudConfiguration;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.log4j.Logger;

@WebListener
public class DatasourceListener implements ServletContextListener {
 
 private static final Logger logger = Logger.getLogger(DatasourceListener.class);

 private CloudConfiguration cloudConfiguration = new CloudConfiguration();
 
 public static final String DATASOURCE_ATTRIBUTE = "dataSource";
 
 @Override
 public void contextInitialized(ServletContextEvent sce) {
  if (!bindCloudDataSource(sce)) {
   logger.warn("not running in the cloud");;
   bindLocalDataSource(sce);
  }//end if
 }

 @Override
 public void contextDestroyed(ServletContextEvent sce) { }

 //creates a "local" (in-memory) binding for testing purposes
 private void bindLocalDataSource(ServletContextEvent sce) {
  //create a database
  BasicDataSource factory = new BasicDataSource();
  factory.setDriverClassName("org.h2.Driver");//TODO - remove hardcoding
  factory.setUrl("jdbc:h2:mem:a");
  factory.setUsername("sa");
  factory.setPassword("");
  //set
  sce.getServletContext().setAttribute(DATASOURCE_ATTRIBUTE, factory);
 }
 
 //runs the cloud configuration component
 private boolean bindCloudDataSource(ServletContextEvent sce) {
  DataSource dataSource = cloudConfiguration.inventoryDataSource();
  if (dataSource != null) {
   sce.getServletContext().setAttribute(DATASOURCE_ATTRIBUTE, dataSource);
   return true;
  }//end if
  return false;
 }
}
3. you're done

a couple of assumptions;
- not using a Dependency Injection container (at all)
- using servlets/etc to pull a datasource object from the servlet context

caveat; this is very crude and will be refined as it gets tested out

No comments:

Post a Comment