001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.spring.transaction;
016    
017    import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
021    import com.liferay.portal.kernel.util.SimplePojoClp;
022    
023    import java.lang.reflect.Method;
024    
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    import javax.annotation.PostConstruct;
029    
030    import org.springframework.transaction.PlatformTransactionManager;
031    import org.springframework.transaction.TransactionDefinition;
032    import org.springframework.transaction.TransactionException;
033    import org.springframework.transaction.TransactionStatus;
034    import org.springframework.transaction.TransactionSystemException;
035    import org.springframework.transaction.support.DefaultTransactionDefinition;
036    
037    /**
038     * <p>
039     * A transaction manager class loader proxy delegating the method invocations to
040     * the transaction manager in the portal implementation. The transaction manager
041     * within the portal must be specified as a Spring bean having id
042     * <code>"liferayTransactionManager"</code>.
043     * </p>
044     *
045     * @author Micha Kiener
046     * @author Brian Wing Shun Chan
047     */
048    public class TransactionManagerClp implements PlatformTransactionManager {
049    
050            public void commit(TransactionStatus transactionStatus)
051                    throws TransactionException {
052    
053                    try {
054                            Method method = _transactionManagerMethods.get("commit");
055    
056                            method.invoke(
057                                    _transactionManager,
058                                    unwrapTransactionStatus(transactionStatus));
059                    }
060                    catch (Exception e) {
061                            _log.error(e, e);
062    
063                            throw new TransactionSystemException(e.getMessage());
064                    }
065            }
066    
067            public TransactionStatus getTransaction(
068                            TransactionDefinition transactionDefinition)
069                    throws TransactionException {
070    
071                    Object transactionStatus = null;
072    
073                    try {
074                            Method method = _transactionManagerMethods.get("getTransaction");
075    
076                            transactionStatus = method.invoke(
077                                    _transactionManager,
078                                    createRemoteTransactionDefinition(transactionDefinition));
079                    }
080                    catch (Exception e) {
081                            _log.error(e, e);
082    
083                            throw new TransactionSystemException(e.getMessage());
084                    }
085    
086                    return new TransactionStatusClp(transactionStatus);
087            }
088    
089            @PostConstruct
090            public void init() throws ClassNotFoundException {
091                    _transactionManager = PortalBeanLocatorUtil.locate(
092                            "liferayTransactionManager");
093    
094                    _transactionDefinitionClp = new SimplePojoClp<TransactionDefinition>(
095                            DefaultTransactionDefinition.class,
096                            PortalClassLoaderUtil.getClassLoader());
097    
098                    initTransactionManagerMethods();
099            }
100    
101            public void rollback(TransactionStatus transactionStatus)
102                    throws TransactionException {
103    
104                    try {
105                            Method method = _transactionManagerMethods.get("rollback");
106    
107                            method.invoke(
108                                    _transactionManager,
109                                    unwrapTransactionStatus(transactionStatus));
110                    }
111                    catch (Exception e) {
112                            _log.error(e, e);
113    
114                            throw new TransactionSystemException(e.getMessage());
115                    }
116            }
117    
118            protected Object createRemoteTransactionDefinition(
119                            TransactionDefinition transactionDefinition)
120                    throws IllegalAccessException, InstantiationException {
121    
122                    return _transactionDefinitionClp.createRemoteObject(
123                            transactionDefinition);
124            }
125    
126            protected void initTransactionManagerMethods() {
127                    _transactionManagerMethods = new HashMap<String, Method>();
128    
129                    Method[] methods = _transactionManager.getClass().getMethods();
130    
131                    for (Method method : methods) {
132                            _transactionManagerMethods.put(method.getName(), method);
133                    }
134            }
135    
136            protected Object unwrapTransactionStatus(
137                    TransactionStatus localTransactionStatus) {
138    
139                    TransactionStatusClp transactionStatusClp =
140                            (TransactionStatusClp)localTransactionStatus;
141    
142                    return transactionStatusClp.getRemoteTransactionStatus();
143            }
144    
145            private static Log _log = LogFactoryUtil.getLog(
146                    TransactionManagerClp.class);
147    
148            private SimplePojoClp<TransactionDefinition> _transactionDefinitionClp;
149            private Object _transactionManager;
150            private Map<String, Method> _transactionManagerMethods;
151    
152    }