Java tutorial
/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.seam.persistence.hibernate; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Collections; import java.util.Set; import javax.enterprise.context.ContextNotActiveException; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.Instance; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.persistence.EntityManager; import javax.transaction.Synchronization; import javax.transaction.SystemException; import org.hibernate.FlushMode; import org.hibernate.Query; import org.hibernate.Session; import org.jboss.seam.persistence.FlushModeType; import org.jboss.seam.persistence.HibernatePersistenceProvider; import org.jboss.seam.persistence.ManagedPersistenceContext; import org.jboss.seam.persistence.PersistenceContexts; import org.jboss.seam.persistence.QueryParser; import org.jboss.seam.persistence.transaction.SeamTransaction; import org.jboss.seam.persistence.transaction.literal.DefaultTransactionLiteral; import org.jboss.seam.persistence.util.InstanceResolver; import org.jboss.weld.extensions.el.Expressions; import org.jboss.weld.extensions.literal.DefaultLiteral; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Proxy handler for the seam managed Hibernate session. This handler makes sure * that the EntityManager is enrolled in the current transaction before passing * the call through to the delegate * * @author Stuart Douglas * */ public class HibernateManagedSessionProxyHandler implements InvocationHandler, Serializable, Synchronization { private static final long serialVersionUID = -6539267789786229774L; private final Session delegate; private final Instance<SeamTransaction> userTransactionInstance; private transient boolean synchronizationRegistered; private PersistenceContexts persistenceContexts; private final Set<Annotation> qualifiers; protected final BeanManager manager; private final HibernatePersistenceProvider provider; private boolean persistenceContextsTouched = false; private boolean closeOnTransactionCommit = false; static final Logger log = LoggerFactory.getLogger(HibernateManagedSessionProxyHandler.class); private final Instance<Expressions> expressionsInstance; public HibernateManagedSessionProxyHandler(Session delegate, BeanManager beanManager, Set<Annotation> qualifiers, HibernatePersistenceProvider provider, BeanManager manager) { this.qualifiers = qualifiers; this.provider = provider; this.delegate = delegate; this.userTransactionInstance = InstanceResolver.getInstance(SeamTransaction.class, beanManager, DefaultTransactionLiteral.INSTANCE); this.expressionsInstance = InstanceResolver.getInstance(Expressions.class, beanManager); this.manager = manager; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { touch((ManagedPersistenceContext) proxy); if ("changeFlushMode".equals(method.getName()) && method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(FlushModeType.class)) { changeFushMode((FlushModeType) args[0]); return null; } if ("getBeanType".equals(method.getName()) && method.getParameterTypes().length == 0) { return EntityManager.class; } if ("getQualifiers".equals(method.getName()) && method.getParameterTypes().length == 0) { return Collections.unmodifiableSet(qualifiers); } if ("getPersistenceProvider".equals(method.getName()) && method.getParameterTypes().length == 0) { return provider; } if ("closeAfterTransaction".equals(method.getName()) && method.getParameterTypes().length == 0) { closeAfterTransaction(); return null; } if ("createQuery".equals(method.getName()) && method.getParameterTypes().length > 0 && method.getParameterTypes()[0].equals(String.class)) { return handleCreateQueryWithString(method, args); } if (!"setFlushMode".equals(method.getName()) && !"getTransaction".equals(method.getName())) { if (!synchronizationRegistered) { joinTransaction(); } } return method.invoke(delegate, args); } protected Object handleCreateQueryWithString(Method method, Object[] args) throws Throwable { if (args[0] == null) { return method.invoke(delegate, args); } String ejbql = (String) args[0]; if (ejbql.indexOf('#') > 0) { QueryParser qp = new QueryParser(expressionsInstance.get(), ejbql); Object[] newArgs = args.clone(); newArgs[0] = qp.getEjbql(); Query query = (Query) method.invoke(delegate, newArgs); for (int i = 0; i < qp.getParameterValues().size(); i++) { query.setParameter(QueryParser.getParameterName(i), qp.getParameterValues().get(i)); } return query; } else { return method.invoke(delegate, args); } } private void joinTransaction() throws SystemException { SeamTransaction transaction = userTransactionInstance.get(); if (transaction.isActive()) { delegate.isOpen(); try { transaction.registerSynchronization(this); synchronizationRegistered = true; } catch (Exception e) { throw new RuntimeException(e); } } } private void closeAfterTransaction() throws SystemException { SeamTransaction transaction = userTransactionInstance.get(); if (transaction.isActive()) { closeOnTransactionCommit = true; } else { if (delegate.isOpen()) { delegate.close(); } } } private void changeFushMode(FlushModeType flushModeType) { switch (flushModeType) { case AUTO: delegate.setFlushMode(FlushMode.AUTO); break; case MANUAL: delegate.setFlushMode(FlushMode.MANUAL); break; case COMMIT: delegate.setFlushMode(FlushMode.COMMIT); break; default: throw new RuntimeException("Unkown flush mode: " + flushModeType); } } void touch(ManagedPersistenceContext delegate) { if (!persistenceContextsTouched) { try { // we need to do this first to prevent an infinite loop persistenceContextsTouched = true; getPersistenceContexts().touch(delegate); } catch (ContextNotActiveException e) { persistenceContextsTouched = false; log.debug("Not touching pc " + this + "as conversation scope not active"); } } } public void afterCompletion(int status) { synchronizationRegistered = false; if (closeOnTransactionCommit && delegate.isOpen()) { delegate.close(); } } public void beforeCompletion() { } private PersistenceContexts getPersistenceContexts() { if (persistenceContexts == null) { Bean<PersistenceContexts> bean = (Bean) manager .resolve(manager.getBeans(PersistenceContexts.class, DefaultLiteral.INSTANCE)); if (bean == null) { throw new RuntimeException("Could not find PersistenceContexts bean"); } CreationalContext<PersistenceContexts> ctx = manager.createCreationalContext(bean); persistenceContexts = (PersistenceContexts) manager.getReference(bean, PersistenceContexts.class, ctx); } return persistenceContexts; } }