Support multiple databases
sunnyawake Dec 4, 2008 3:57 AMmy company is investigating using Seam as our framework. one of the requests is supporting multiple databases for different customers with almost the same set of java code and pages.
i used the dvdstore sample and did the following changes:
1. changed all @PersistenceContext to @In
2. in AuthenticationAction,added a companyId field for login.xhtml. after authentication,outject the companyId to sessionContext.
3. changed components.xml:
......
<persistence:managed-persistence-context auto-create="true"
name="entityManager" />
<persistence:managed-persistence-context auto-create="true"
name="company1_em" />
<persistence:managed-persistence-context auto-create="true"
name="company2_em" />
<factory auto-create="true" name="order" scope="stateless" value="#{orderHome.instance}"/>
<framework:entity-home auto-create="true"
entity-class="com.jboss.dvd.seam.Order" name="orderHome" scope="conversation" entity-manager="#{platform.entityManager}">
<framework:id>#{orderId}</framework:id>
</framework:entity-home>
<framework:entity-query ejbql="select c from Category c"
name="allCategories" order="c.name" entity-manager="#{platform.entityManager}">
</framework:entity-query>
<factory name="topProducts" value="#{topQuery.resultList}"/>
<framework:entity-query ejbql="select p from Product p" max-results="8"
name="topQuery" order="p.inventory.sales desc" entity-manager="#{platform.entityManager}"/>4. add Platform.java:
@Name("platform")
public class Platform {
public static final String KEY_COMPANYID="com.longkey.system.companyId";
public static final String SUFFIX_EM = "_em";
public static final String SUFFIX_JBPMCONTEXT = "";
public static final String SUFFIX_DATASOURCE = "_dvdDatasource";
public static String[] getCompanyIds() {
return new String[]{"company1","company2"};
}
public EntityManager getEntityManager(){
String companyId=(String)Contexts.getSessionContext().get(KEY_COMPANYID);
return (EntityManager)Component.getInstance(companyId+SUFFIX_EM);
}5. changed ManagedPersistenceContext.java:
........
@Create
public void create(Component component)
{
this.componentName = component.getName();
if(componentName.equals("entityManager")){
componentName=Contexts.getSessionContext().get(Platform.KEY_COMPANYID)+Platform.SUFFIX_EM;
}6. in persistence.xml,jbpm.cfg.xml and xxx-ds.xml,added entries for each company. in hibernate.cfg.xml,commented out datasource property,which i specified in Jbpm.java when seam startup:
private void initJbpmConfiguration()
{
if (jbpmConfigurationJndiName==null)
{
jbpmConfiguration = JbpmConfiguration.getInstance();
}
else
{
try
{
jbpmConfiguration = (JbpmConfiguration) Naming.getInitialContext().lookup(jbpmConfigurationJndiName);
}
catch (NamingException ne)
{
throw new IllegalArgumentException("JbpmConfiguration not found in JNDI", ne);
}
}
DbPersistenceServiceFactory defaultFactory = (DbPersistenceServiceFactory) jbpmConfiguration.getServiceFactory("persistence");
if (Naming.getInitialContextProperties()!=null)
{
// Prefix regular JNDI properties for Hibernate
Hashtable<String, String> hash = Naming.getInitialContextProperties();
Properties prefixed = new Properties();
for (Map.Entry<String, String> entry: hash.entrySet() )
{
prefixed.setProperty( Environment.JNDI_PREFIX + "." + entry.getKey(), entry.getValue() );
}
try
{
defaultFactory.getConfiguration().getProperties().putAll(prefixed);
}
catch (HibernateException he)
{
log.info("could not set JNDI properties for jBPM persistence: " + he.getMessage());
}
}
//sunny build session factory for each company
Configuration cfg=defaultFactory.getConfiguration();
String[] companyIds=Platform.getCompanyIds();
for(String companyId:companyIds){
DbPersistenceServiceFactory factory = (DbPersistenceServiceFactory) jbpmConfiguration.getServiceFactory("persistence",companyId+Platform.SUFFIX_JBPMCONTEXT);
factory.setConfiguration(cfg);
cfg.setProperty(Environment.DATASOURCE, "java:/"+companyId+Platform.SUFFIX_DATASOURCE);
factory.getSessionFactory();
}
}after these changes, something weird happens. in AuthenticationAction the outjected currentUser
is always lost somewhere before i reach the checkout
page,which causes CheckoutAction.submitOrder throw exceptions and not be able to lauch OrderManagement
workflow.
Seam:2.1.0.SP1,JBoss:4.2.3.GA