private Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker>
      createEntityManagers(BeanContext beanContext) {
    // create the extended entity managers
    Index<EntityManagerFactory, Map> factories = beanContext.getExtendedEntityManagerFactories();
    Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers =
        null;
    if (factories != null && factories.size() > 0) {
      entityManagers =
          new Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker>(
              new ArrayList<EntityManagerFactory>(factories.keySet()));
      for (Map.Entry<EntityManagerFactory, Map> entry : factories.entrySet()) {
        EntityManagerFactory entityManagerFactory = entry.getKey();
        Map properties = entry.getValue();

        JtaEntityManagerRegistry.EntityManagerTracker entityManagerTracker =
            entityManagerRegistry.getInheritedEntityManager(entityManagerFactory);
        EntityManager entityManager;
        if (entityManagerTracker == null) {
          if (properties != null) {
            entityManager = entityManagerFactory.createEntityManager(properties);
          } else {
            entityManager = entityManagerFactory.createEntityManager();
          }
          entityManagerTracker = new JtaEntityManagerRegistry.EntityManagerTracker(entityManager);
        } else {
          entityManagerTracker.incCounter();
        }
        entityManagers.put(entityManagerFactory, entityManagerTracker);
      }
    }
    return entityManagers;
  }
  private void unregisterEntityManagers(Instance instance, ThreadContext callContext) {
    if (entityManagerRegistry == null) return;
    if (instance == null) return;

    BeanContext beanContext = callContext.getBeanContext();

    // register them
    entityManagerRegistry.removeEntityManagers(
        (String) beanContext.getDeploymentID(), instance.primaryKey);
  }
  private void registerEntityManagers(Instance instance, ThreadContext callContext)
      throws OpenEJBException {
    if (entityManagerRegistry == null) return;

    BeanContext beanContext = callContext.getBeanContext();

    // get the factories
    Index<EntityManagerFactory, Map> factories = beanContext.getExtendedEntityManagerFactories();
    if (factories == null) return;

    // get the managers for the factories
    Map<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers =
        instance.getEntityManagers(factories);
    if (entityManagers == null) return;

    // register them
    try {
      entityManagerRegistry.addEntityManagers(
          (String) beanContext.getDeploymentID(), instance.primaryKey, entityManagers);
    } catch (EntityManagerAlreadyRegisteredException e) {
      throw new EJBException(e);
    }
  }
  protected ProxyInfo createEJBObject(
      BeanContext beanContext, Method callMethod, Object[] args, InterfaceType interfaceType)
      throws OpenEJBException {
    // generate a new primary key
    Object primaryKey = newPrimaryKey();

    ThreadContext createContext = new ThreadContext(beanContext, primaryKey);
    ThreadContext oldCallContext = ThreadContext.enter(createContext);
    try {
      // Security check
      checkAuthorization(callMethod, interfaceType);

      // Create the extended entity managers for this instance
      Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers =
          createEntityManagers(beanContext);

      // Register the newly created entity managers
      if (entityManagers != null) {
        try {
          entityManagerRegistry.addEntityManagers(
              (String) beanContext.getDeploymentID(), primaryKey, entityManagers);
        } catch (EntityManagerAlreadyRegisteredException e) {
          throw new EJBException(e);
        }
      }

      createContext.setCurrentOperation(Operation.CREATE);
      createContext.setCurrentAllowedStates(null);

      // Start transaction
      TransactionPolicy txPolicy =
          createTransactionPolicy(
              createContext.getBeanContext().getTransactionType(callMethod, interfaceType),
              createContext);

      Instance instance = null;
      try {
        // Create new instance

        try {
          final InstanceContext context = beanContext.newInstance();

          // Wrap-up everthing into a object
          instance =
              new Instance(
                  beanContext,
                  primaryKey,
                  context.getBean(),
                  context.getInterceptors(),
                  context.getCreationalContext(),
                  entityManagers);

        } catch (Throwable throwable) {
          ThreadContext callContext = ThreadContext.getThreadContext();
          handleSystemException(callContext.getTransactionPolicy(), throwable, callContext);
          throw new IllegalStateException(throwable); // should never be reached
        }

        // add to cache
        cache.add(primaryKey, instance);

        // instance starts checked-out
        checkedOutInstances.put(primaryKey, instance);

        // Register for synchronization callbacks
        registerSessionSynchronization(instance, createContext);

        // Invoke create for legacy beans
        if (!callMethod.getDeclaringClass().equals(BeanContext.BusinessLocalHome.class)
            && !callMethod.getDeclaringClass().equals(BeanContext.BusinessRemoteHome.class)
            && !callMethod.getDeclaringClass().equals(BeanContext.BusinessLocalBeanHome.class)) {

          // Setup for business invocation
          Method createOrInit = beanContext.getMatchingBeanMethod(callMethod);
          createContext.set(Method.class, createOrInit);

          // Initialize interceptor stack
          InterceptorStack interceptorStack =
              new InterceptorStack(
                  instance.bean,
                  createOrInit,
                  Operation.CREATE,
                  new ArrayList<InterceptorData>(),
                  new HashMap<String, Object>());

          // Invoke
          if (args == null) {
            interceptorStack.invoke();
          } else {
            interceptorStack.invoke(args);
          }
        }
      } catch (Throwable e) {
        handleException(createContext, txPolicy, e);
      } finally {
        afterInvoke(createContext, txPolicy, instance);
      }

      return new ProxyInfo(beanContext, primaryKey);
    } finally {
      ThreadContext.exit(oldCallContext);
    }
  }