debop4k.data.orm.jpa.stateless.StatelessSessionFactoryBean.java Source code

Java tutorial

Introduction

Here is the source code for debop4k.data.orm.jpa.stateless.StatelessSessionFactoryBean.java

Source

/*
 * Copyright (c) 2016. Sunghyouk Bae <sunghyouk.bae@gmail.com>
 * 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 debop4k.data.orm.jpa.stateless;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.MethodInvocation;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.internal.SessionImpl;
import org.hibernate.internal.StatelessSessionImpl;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.ReflectionUtils;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.sql.Connection;

/**
 * Hibernate ? {@link StatelessSession}? JPA?   ??, {@link StatelessSession}? ? Factory Bean.
 *  : https://gist.github.com/jelies/5181262
 *
 * @author sunghyouk.bae@gmail.com
 */
@Slf4j
public class StatelessSessionFactoryBean implements FactoryBean<StatelessSession> {

    private final EntityManagerFactory emf;
    private final SessionFactory sf;

    @Inject
    public StatelessSessionFactoryBean(HibernateEntityManagerFactory emf) {
        this.emf = emf;
        this.sf = emf.getSessionFactory();
    }

    @Override
    public StatelessSession getObject() throws Exception {
        StatelessSessionInterceptor interceptor = new StatelessSessionInterceptor(emf, sf);
        return ProxyFactory.getProxy(StatelessSession.class, interceptor);
    }

    @Override
    public Class<?> getObjectType() {
        return StatelessSession.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    /**
     * StatelessSession interceptor
     */
    class StatelessSessionInterceptor implements org.aopalliance.intercept.MethodInterceptor {

        private final EntityManagerFactory emf;
        private final SessionFactory sf;

        public StatelessSessionInterceptor(EntityManagerFactory emf, SessionFactory sf) {
            this.emf = emf;
            this.sf = sf;
        }

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            StatelessSession stateless = getCurrentStateless();
            return ReflectionUtils.invokeMethod(invocation.getMethod(), stateless, invocation.getArguments());
        }

        private StatelessSession getCurrentStateless() {
            if (!TransactionSynchronizationManager.isActualTransactionActive()) {
                throw new IllegalStateException(
                        " ? ? ? . StatelessSession ? Transaction ? ??.");
            }

            StatelessSession stateless = (StatelessSession) TransactionSynchronizationManager.getResource(sf);
            if (stateless == null) {
                log.debug(" ?  Stateless Session ? ?.");
                stateless = newStatelessSession();
                bindWithTransaction(stateless);
            }
            return stateless;
        }

        private StatelessSession newStatelessSession() {
            Connection conn = obtainPhysicalConnection();
            return sf.openStatelessSession(conn);
        }

        public Connection obtainPhysicalConnection() {
            log.debug("Proxy   Physical Connection? ...");
            EntityManager em = EntityManagerFactoryUtils.getTransactionalEntityManager(emf);

            SessionImpl session = (SessionImpl) em.unwrap(Session.class);

            return session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection();
        }

        public void bindWithTransaction(StatelessSession stateless) {
            log.trace("bind with transaction");
            TransactionSynchronizationManager
                    .registerSynchronization(new StatelessSessionSynchronization(sf, stateless));

            TransactionSynchronizationManager.bindResource(sf, stateless);
        }
    }

    @Getter
    static class StatelessSessionSynchronization extends TransactionSynchronizationAdapter {

        private final SessionFactory sf;
        private final StatelessSession stateless;

        public StatelessSessionSynchronization(SessionFactory sf, StatelessSession stateless) {
            this.sf = sf;
            this.stateless = stateless;
        }

        @Override
        public int getOrder() {
            return EntityManagerFactoryUtils.ENTITY_MANAGER_SYNCHRONIZATION_ORDER - 100;
        }

        @Override
        public void beforeCommit(boolean readOnly) {
            if (!readOnly) {
                ((StatelessSessionImpl) stateless).flushBeforeTransactionCompletion();
            }
        }

        @Override
        public void beforeCompletion() {
            TransactionSynchronizationManager.unbindResource(sf);
            stateless.close();
        }
    }
}