org.activityinfo.server.endpoint.gwtrpc.AdvisoryLock.java Source code

Java tutorial

Introduction

Here is the source code for org.activityinfo.server.endpoint.gwtrpc.AdvisoryLock.java

Source

package org.activityinfo.server.endpoint.gwtrpc;
/*
 * #%L
 * ActivityInfo Server
 * %%
 * Copyright (C) 2009 - 2013 UNICEF
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public 
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/gpl-3.0.html>.
 * #L%
 */

import com.google.common.base.Preconditions;
import com.google.common.base.Stopwatch;
import org.activityinfo.legacy.shared.exception.CommandTimeoutException;
import org.activityinfo.legacy.shared.exception.UnexpectedCommandException;
import org.hibernate.Query;
import org.hibernate.ejb.HibernateEntityManager;

import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author yuriyz on 10/10/2014.
 */
public class AdvisoryLock implements AutoCloseable {

    private static final Logger LOGGER = Logger.getLogger(AdvisoryLock.class.getName());

    public static final String ADVISORY_LOCK_NAME = "activityinfo.remote_execution_context";

    public static final int ADVISORY_GET_LOCK_TIMEOUT = 10;
    public static final int SUCCESS_CODE = 1;
    private static final int TIMEOUT_CODE = 0;

    private final HibernateEntityManager entityManager;

    public AdvisoryLock(HibernateEntityManager entityManager) {
        Preconditions.checkNotNull(entityManager);

        this.entityManager = entityManager;

        try {
            Stopwatch stopwatch = Stopwatch.createStarted();

            String sql = String.format("SELECT GET_LOCK('%s', %s)", ADVISORY_LOCK_NAME, ADVISORY_GET_LOCK_TIMEOUT);

            Query query = entityManager.getSession().createSQLQuery(sql);
            Object result = query.uniqueResult();

            if (result == null) {
                throw new UnexpectedCommandException("Error occurred while trying to obtain advisory lock.");
            }

            int resultCode = ((Number) result).intValue();
            if (resultCode == TIMEOUT_CODE) { // time out
                LOGGER.severe("Timed out waiting for write lock.");
                throw new CommandTimeoutException();
            }

            if (resultCode != SUCCESS_CODE) { // not success
                LOGGER.severe("Failed to acquire lock, result code: " + resultCode);
                throw new RuntimeException("Failed to acquire lock, result code: " + resultCode);
            }

            stopwatch.stop();
            LOGGER.finest("Acquiring advisory lock takes: " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");
        } catch (CommandTimeoutException e) {
            throw e;
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Internal error during acquiring advisory lock: " + e.getMessage(), e);
            throw new RuntimeException("Exception caught while trying to acquire update lock", e);
        }
    }

    @Override
    public void close() throws Exception {
        Stopwatch stopwatch = Stopwatch.createStarted();
        String sql = String.format("SELECT RELEASE_LOCK('%s')", ADVISORY_LOCK_NAME);

        Query query = entityManager.getSession().createSQLQuery(sql);
        Object result = query.uniqueResult();
        int resultCode = ((Number) result).intValue();
        if (resultCode != SUCCESS_CODE) {
            throw new RuntimeException("Failed to release lock, result code: " + resultCode);
        }

        stopwatch.stop();
        LOGGER.finest("Release lock takes: " + stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");
    }

    public void closeQuietly() {
        try {
            close();
        } catch (Exception e) {
            LOGGER.log(Level.SEVERE, "Failed to release lock.", e);
        }
    }

    public static void closeQuietly(AdvisoryLock lock) {
        if (lock != null) {
            lock.closeQuietly();
        }
    }
}