Open Source Repository

Home /spring/spring-orm-3.0.5 | Repository Home


org/springframework/orm/jpa/vendor/OpenJpaDialect.java
/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.orm.jpa.vendor;

import java.sql.Connection;
import java.sql.SQLException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;

import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.datasource.ConnectionHolder;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.orm.jpa.DefaultJpaDialect;
import org.springframework.transaction.SavepointManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;

/**
 {@link org.springframework.orm.jpa.JpaDialect} implementation for
 * Apache OpenJPA. Developed and tested against OpenJPA 0.9.7.
 *
 @author Costin Leau
 @author Juergen Hoeller
 @since 2.0
 */
public class OpenJpaDialect extends DefaultJpaDialect {

  @Override
  public Object beginTransaction(EntityManager entityManager, TransactionDefinition definition)
      throws PersistenceException, SQLException, TransactionException {

    super.beginTransaction(entityManager, definition);
    OpenJPAEntityManager em = getOpenJPAEntityManager(entityManager);
    if (!definition.isReadOnly()) {
      // Like with TopLink, make sure to start the logic transaction early so that other
      // participants using the connection (such as JdbcTemplate) run in a transaction.
      em.beginStore();
    }
    return new OpenJpaTransactionData(em);
  }

  @Override
  public ConnectionHandle getJdbcConnection(EntityManager entityManager, boolean readOnly)
      throws PersistenceException, SQLException {

    return new OpenJpaConnectionHandle(getOpenJPAEntityManager(entityManager));
  }

  /**
   * Return the OpenJPA-specific interface of <code>EntityManager</code>.
   @param em the generic <code>EntityManager</code> instance
   @return the OpenJPA-specific interface of <code>EntityManager</code>
   */
  protected OpenJPAEntityManager getOpenJPAEntityManager(EntityManager em) {
    return OpenJPAPersistence.cast(em);
  }


  /**
   * Transaction data Object exposed from <code>beginTransaction</code>,
   * implementing the SavepointManager interface.
   */
  private static class OpenJpaTransactionData implements SavepointManager {

    private final OpenJPAEntityManager entityManager;

    private int savepointCounter = 0;

    public OpenJpaTransactionData(OpenJPAEntityManager entityManager) {
      this.entityManager = entityManager;
    }

    public Object createSavepoint() throws TransactionException {
      this.savepointCounter++;
      String savepointName = ConnectionHolder.SAVEPOINT_NAME_PREFIX + this.savepointCounter;
      this.entityManager.setSavepoint(savepointName);
      return savepointName;
    }

    public void rollbackToSavepoint(Object savepointthrows TransactionException {
      this.entityManager.rollbackToSavepoint((Stringsavepoint);
    }

    public void releaseSavepoint(Object savepointthrows TransactionException {
      this.entityManager.releaseSavepoint((Stringsavepoint);
    }
  }


  /**
   * ConnectionHandle implementation that fetches a new OpenJPA-provided Connection
   * for every <code>getConnection</code> call and closes the Connection on
   <code>releaseConnection</code>. This is necessary because OpenJPA requires the
   * fetched Connection to be closed before continuing EntityManager work.
   @see org.apache.openjpa.persistence.OpenJPAEntityManager#getConnection()
   */
  private static class OpenJpaConnectionHandle implements ConnectionHandle {

    private final OpenJPAEntityManager entityManager;

    public OpenJpaConnectionHandle(OpenJPAEntityManager entityManager) {
      this.entityManager = entityManager;
    }

    public Connection getConnection() {
      return (Connectionthis.entityManager.getConnection();
    }

    public void releaseConnection(Connection con) {
      JdbcUtils.closeConnection(con);
    }
  }

}