001    /**
002     * Copyright (c) 2000-2013 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            @Override
051            public void commit(TransactionStatus transactionStatus)
052                    throws TransactionException {
053    
054                    try {
055                            Method method = _transactionManagerMethods.get("commit");
056    
057                            method.invoke(
058                                    _transactionManager,
059                                    unwrapTransactionStatus(transactionStatus));
060                    }
061                    catch (Exception e) {
062                            _log.error(e, e);
063    
064                            throw new TransactionSystemException(e.getMessage());
065                    }
066            }
067    
068            @Override
069            public TransactionStatus getTransaction(
070                            TransactionDefinition transactionDefinition)
071                    throws TransactionException {
072    
073                    Object transactionStatus = null;
074    
075                    try {
076                            Method method = _transactionManagerMethods.get("getTransaction");
077    
078                            transactionStatus = method.invoke(
079                                    _transactionManager,
080                                    createRemoteTransactionDefinition(transactionDefinition));
081                    }
082                    catch (Exception e) {
083                            _log.error(e, e);
084    
085                            throw new TransactionSystemException(e.getMessage());
086                    }
087    
088                    return new TransactionStatusClp(transactionStatus);
089            }
090    
091            @PostConstruct
092            public void init() throws ClassNotFoundException {
093                    _transactionManager = PortalBeanLocatorUtil.locate(
094                            "liferayTransactionManager");
095    
096                    _transactionDefinitionClp = new SimplePojoClp<TransactionDefinition>(
097                            DefaultTransactionDefinition.class,
098                            PortalClassLoaderUtil.getClassLoader());
099    
100                    initTransactionManagerMethods();
101            }
102    
103            @Override
104            public void rollback(TransactionStatus transactionStatus)
105                    throws TransactionException {
106    
107                    try {
108                            Method method = _transactionManagerMethods.get("rollback");
109    
110                            method.invoke(
111                                    _transactionManager,
112                                    unwrapTransactionStatus(transactionStatus));
113                    }
114                    catch (Exception e) {
115                            _log.error(e, e);
116    
117                            throw new TransactionSystemException(e.getMessage());
118                    }
119            }
120    
121            protected Object createRemoteTransactionDefinition(
122                            TransactionDefinition transactionDefinition)
123                    throws IllegalAccessException, InstantiationException {
124    
125                    return _transactionDefinitionClp.createRemoteObject(
126                            transactionDefinition);
127            }
128    
129            protected void initTransactionManagerMethods() {
130                    _transactionManagerMethods = new HashMap<String, Method>();
131    
132                    Method[] methods = _transactionManager.getClass().getMethods();
133    
134                    for (Method method : methods) {
135                            _transactionManagerMethods.put(method.getName(), method);
136                    }
137            }
138    
139            protected Object unwrapTransactionStatus(
140                    TransactionStatus localTransactionStatus) {
141    
142                    TransactionStatusClp transactionStatusClp =
143                            (TransactionStatusClp)localTransactionStatus;
144    
145                    return transactionStatusClp.getRemoteTransactionStatus();
146            }
147    
148            private static Log _log = LogFactoryUtil.getLog(
149                    TransactionManagerClp.class);
150    
151            private SimplePojoClp<TransactionDefinition> _transactionDefinitionClp;
152            private Object _transactionManager;
153            private Map<String, Method> _transactionManagerMethods;
154    
155    }