SyntaxHighlighter

Showing posts with label CloudFoundry. Show all posts
Showing posts with label CloudFoundry. Show all posts

Wednesday, July 9, 2014

HttpSession Failover - Spring Session

HttpSession Failover - Spring Session

Spring Session 1.0.0M1 was announced recently and it's a great answer to HttpSession failover.  


essentially it allows you to architect this;

- multiple instances of a webapp connected by redis (or any other bus) to share httpsession objects

the trick to remember is that you no longer need sticky sessions; just hit any server you like as the session data is replicated and shared to all members talking to the same redis server.

put this on CloudFoundry and you're really cooking; scale up and down the web apps without any worries about HttpSession loss and stickiness


(and to see it in a really really rough test, check out redis-session.cfapps.io)

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