0 Replies Latest reply on Dec 4, 2008 3:57 AM by sunnyawake

    Support multiple databases

    sunnyawake

      my 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