All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.granite.tide.spring.TideDataPublishingWrapper Maven / Gradle / Ivy

The newest version!
/**
 *   GRANITE DATA SERVICES
 *   Copyright (C) 2006-2014 GRANITE DATA SERVICES S.A.S.
 *
 *   This file is part of the Granite Data Services Platform.
 *
 *   Granite Data Services 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.
 *
 *   Granite Data Services 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 library; if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
 *   USA, or see .
 */
package org.granite.tide.spring;

import org.granite.gravity.Gravity;
import org.granite.logging.Logger;
import org.granite.tide.data.DataContext;
import org.granite.tide.data.DataEnabled;
import org.granite.tide.data.DataEnabled.PublishMode;
import org.granite.tide.data.DataUpdatePostprocessor;
import org.granite.tide.data.TideSynchronizationManager;
import org.granite.util.ThrowableCallable;
import org.granite.util.TypeUtil;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.HashMap;
import java.util.Map;

/**
 * Common class to implement data enabled interceptors
 */
public class TideDataPublishingWrapper {

    private static final Logger log = Logger.getLogger(TideDataPublishingWrapper.class);

    private Map syncsMap = new HashMap();

    private Gravity gravity;
    private DataUpdatePostprocessor dataUpdatePostprocessor;

    public void setGravity(Gravity gravity) {
        this.gravity = gravity;
    }

    public void setDataUpdatePostprocessor(DataUpdatePostprocessor dataUpdatePostprocessor) {
        this.dataUpdatePostprocessor = dataUpdatePostprocessor;
    }

    public TideDataPublishingWrapper() {
        try {
            syncsMap.put("org.springframework.orm.hibernate3.SessionHolder", TypeUtil.newInstance("org.granite.tide.spring.Hibernate3SynchronizationManager", TideSynchronizationManager.class));
        }
        catch (Throwable e) {
            // Hibernate 3 not present
        }
        try {
            syncsMap.put("org.springframework.orm.hibernate4.SessionHolder", TypeUtil.newInstance("org.granite.tide.spring.Hibernate4SynchronizationManager", TideSynchronizationManager.class));
        }
        catch (Throwable e) {
            // Hibernate 4 not present
        }
        try {
            syncsMap.put("org.springframework.orm.jpa.EntityManagerHolder", TypeUtil.newInstance("org.granite.tide.spring.JPASynchronizationManager", TideSynchronizationManager.class));
        }
        catch (Throwable e) {
            // JPA not present
        }
    }

    public TideDataPublishingWrapper(Gravity gravity, DataUpdatePostprocessor dataUpdatePostprocessor) {
        this();
        this.gravity = gravity;
        this.dataUpdatePostprocessor = dataUpdatePostprocessor;
    }

    public  T execute(DataEnabled dataEnabled, ThrowableCallable action) throws Throwable {
        boolean shouldRemoveContextAtEnd = DataContext.get() == null;
        boolean shouldInitContext = shouldRemoveContextAtEnd || DataContext.isNull();
        boolean onCommit = false;

        if (shouldInitContext) {
            DataContext.init(gravity, dataEnabled.topic(), dataEnabled.params(), dataEnabled.publish());
            if (dataUpdatePostprocessor != null)
                DataContext.get().setDataUpdatePostprocessor(dataUpdatePostprocessor);
        }

        DataContext.observe();
        try {
            if (dataEnabled.publish().equals(PublishMode.ON_COMMIT) && !TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
                if (TransactionSynchronizationManager.isSynchronizationActive()) {
                    boolean registered = false;
                    for (Object resource : TransactionSynchronizationManager.getResourceMap().values()) {
                        if (syncsMap.containsKey(resource.getClass().getName())) {
                            registered = syncsMap.get(resource.getClass().getName()).registerSynchronization(resource, shouldRemoveContextAtEnd);
                            break;
                        }
                    }
                    if (!registered)
                        TransactionSynchronizationManager.registerSynchronization(new DataPublishingTransactionSynchronization(shouldRemoveContextAtEnd));
                    else if (shouldRemoveContextAtEnd)
                        TransactionSynchronizationManager.registerSynchronization(new DataContextCleanupTransactionSynchronization());
                    onCommit = true;
                }
                else if (TransactionSynchronizationManager.isActualTransactionActive()) {
                    log.error("Could not register synchronization for ON_COMMIT publish mode, check that the Spring PlatformTransactionManager supports it "
                            + "and that the order of the TransactionInterceptor is lower than the order of TideDataPublishingInterceptor");
                    if (shouldRemoveContextAtEnd)
                        DataContext.remove();
                }
                else {
                    // No transaction, clear data context and wait for a possible manual transactions
                    if (shouldRemoveContextAtEnd)
                        DataContext.remove();
                }
            }

            T ret = action.call();

            DataContext.publish(PublishMode.ON_SUCCESS);
            return ret;
        }
        finally {
            if (shouldRemoveContextAtEnd && !onCommit)
                DataContext.remove();
        }
    }

    private static class DataPublishingTransactionSynchronization extends TransactionSynchronizationAdapter {

        private boolean removeContext = false;

        public DataPublishingTransactionSynchronization(boolean removeContext) {
            this.removeContext = removeContext;
        }

        @Override
        public void beforeCommit(boolean readOnly) {
            if (!readOnly)
                DataContext.publish(PublishMode.ON_COMMIT);
        }

        @Override
        public void beforeCompletion() {
            if (removeContext)
                DataContext.remove();
        }

        @Override
        public void afterCompletion(int status) {
            if (removeContext)
                DataContext.remove();
        }
    }

    private static class DataContextCleanupTransactionSynchronization extends TransactionSynchronizationAdapter {

        @Override
        public void afterCompletion(int status) {
            DataContext.remove();
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy