@Override
  public void beforeInvocation() {
    //
    // Prevent the regular JPA Plugin from starting a transaction.
    //
    JPA.entityManagerFactory = null;

    //
    //	If we have no databases defined, and we have a directive to permit this state, allow it.
    //
    if (factoryMap.isEmpty()
        && Play.configuration.getProperty("mjpa.runWithNoDB", "").equals("true")) {
      log.debug("Empty factory map--using dummy factory");
      JPA.entityManagerFactory = getDummyFactory();
      return;
    }

    log.debug("Extracting DB key from request: " + Request.current());

    //
    // Find the database key, so that we'll have one for the transaction.
    //
    String dbKey = keyExtractor.extractKey(Request.current());
    log.debug("Found key: " + dbKey);
    try {
      if (dbKey != null) {
        //
        // Start the transaction
        //
        startTx(dbKey, false);
      }
    } catch (InvalidDatabaseException e) {
      throw new NotFound(e.getMessage());
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  public void onApplicationStart() {
    //
    //	NOTE: this uses the JPA class to store the request's entityManagerFactory.
    //	The trick is that the MJPAPlugin has higher priority than Play's native JPAPlugin.
    //
    if (JPA.entityManagerFactory == null) {
      List<Class> classes = Play.classloader.getAnnotatedClasses(Entity.class);
      if (classes.isEmpty() && Play.configuration.getProperty("jpa.entities", "").equals("")) {
        return;
      }
      if (MDB.datasources == null || MDB.datasources.isEmpty()) {
        if (Play.configuration.getProperty("mjpa.runWithNoDB", "").equals("true")) {
          //
          //	Create a dummy entity manager factory, so that JPA is prevented from screaming.
          //
          JPA.entityManagerFactory = getDummyFactory();
          log.info(
              "No properly configured databases found.  JPA will not be initialized until databases are added");
        } else {
          throw new JPAException(
              "Cannot start a MJPA manager without a properly configured database",
              new NullPointerException("No datasource configured"));
        }
      } else {
        //
        //	Iterate over the datasources and build a configuration for each.
        //
        for (Entry<String, DataSource> entry : MDB.datasources.entrySet()) {
          ComboPooledDataSource datasource = (ComboPooledDataSource) entry.getValue();

          Ejb3Configuration cfg = buildEjbConfiguration(classes, datasource);
          Logger.trace("Initializing JPA ...");
          try {
            EntityManagerFactory factory = cfg.buildEntityManagerFactory();
            JPA.entityManagerFactory = factory;
            factoryMap.put(entry.getKey(), factory);
            log.debug("Added datasource: " + datasource.getJdbcUrl());
          } catch (PersistenceException e) {
            throw new JPAException(e.getMessage(), e.getCause() != null ? e.getCause() : e);
          }
        }
      }
      JPQLDialect.instance = new JPQLDialect();
    }

    //
    //	Set up the key extractor here, by looking for an application class that implements it.
    //
    List<Class> extractors = Play.classloader.getAssignableClasses(RequestDBKeyExtractor.class);
    if (extractors.size() > 1) {
      throw new JPAException(
          "Too many DB Key extract classes.  "
              + "The Multiple DB plugin must use a single extractor class to "
              + "specify its extractor.  These classes where found: "
              + extractors);
    } else if (!extractors.isEmpty()) {
      Class clazz = extractors.get(0);
      try {
        keyExtractor = (RequestDBKeyExtractor) clazz.newInstance();
      } catch (InstantiationException e) {
        log.error("Unable to instantiate extractor class:", e);
      } catch (IllegalAccessException e) {
        log.error("Invalid access to extractor class:", e);
      }
      log.debug("Using application DB key extractor class: " + keyExtractor.getClass().getName());
    } else {
      log.debug("Using default DB key extractor class: " + keyExtractor.getClass().getName());
    }
  }