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