com.smartitengineering.cms.spi.lock.impl.distributed.LocalLockRegistrarImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.smartitengineering.cms.spi.lock.impl.distributed.LocalLockRegistrarImpl.java

Source

/*
 *
 * This is a simple Content Management System (CMS)
 * Copyright (C) 2011 Imran M Yousuf (imyousuf@smartitengineering.com)
 *
 * 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/>.
 */
package com.smartitengineering.cms.spi.lock.impl.distributed;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.google.inject.name.Named;
import com.smartitengineering.cms.spi.lock.Key;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author imyousuf
 */
@Singleton
public class LocalLockRegistrarImpl implements LocalLockRegistrar {

    private final AtomicLong longFactory = new AtomicLong(0);
    private final ReentrantLock lock = new ReentrantLock();
    private final Map<Key, LockDetails> lockMap = new HashMap<Key, LockDetails>();
    private final Timer timer = new Timer();
    protected final transient Logger logger = LoggerFactory.getLogger(getClass());
    @Inject(optional = true)
    @Named("localLockTimeout")
    private int localLockTimeout = 2 * 60 * 1000;

    @Inject
    public void initTimeoutChecking() {
        timer.schedule(new TimerTask() {

            @Override
            public void run() {
                lock.lock();
                List<Entry<Key, LockDetails>> removables = new ArrayList<Entry<Key, LockDetails>>();
                try {
                    long currentTime = System.currentTimeMillis();

                    final Set<Entry<Key, LockDetails>> entrySet = lockMap.entrySet();
                    for (Entry<Key, LockDetails> entry : entrySet) {
                        if (currentTime >= entry.getValue().getTimeoutTime()) {
                            removables.add(
                                    new SimpleEntry<Key, LockDetails>(entry.getKey(), lockMap.get(entry.getKey())));
                        }
                    }
                } catch (Exception ex) {
                    logger.warn(ex.getMessage(), ex);
                } finally {
                    lock.unlock();
                }
                for (Entry<Key, LockDetails> removable : removables) {
                    unlock(removable.getKey(), removable.getValue().getLockId());
                    removable.getValue().getListener().lockTimedOut(removable.getKey());
                }
            }
        }, localLockTimeout, localLockTimeout);
    }

    public String lock(Key key, LockTimeoutListener listener, long waitTime) {
        long availableWaitTime = waitTime;
        while (true) {
            lock.lock();
            try {
                if (!lockMap.containsKey(key)) {
                    final String id = String.valueOf(longFactory.incrementAndGet());
                    LockDetails details = new LockDetails((System.currentTimeMillis() + localLockTimeout), id,
                            listener);
                    lockMap.put(key, details);
                    return id;
                }
            } catch (Exception ex) {
                logger.warn(ex.getMessage(), ex);
            } finally {
                lock.unlock();
            }
            if (availableWaitTime <= 0) {
                return null;
            } else {
                long startTime = 0;
                try {
                    synchronized (this) {
                        startTime = System.currentTimeMillis();
                        wait(availableWaitTime);
                    }
                } catch (Exception ex) {
                    logger.warn(ex.getMessage(), ex);
                }
                availableWaitTime = availableWaitTime - (System.currentTimeMillis() - startTime);
            }
        }
    }

    public boolean unlock(Key key, String lockId) {
        if (StringUtils.isBlank(lockId)) {
            return false;
        }
        lock.lock();
        try {
            if (lockMap.containsKey(key)) {
                if (lockId.equals(lockMap.get(key).getLockId())) {
                    lockMap.remove(key);
                    synchronized (this) {
                        notifyAll();
                    }
                    return true;
                }
            }
        } catch (Exception ex) {
            logger.warn(ex.getMessage(), ex);
        } finally {
            lock.unlock();
        }
        return false;
    }

    private static class LockDetails {

        private final long timeoutTime;
        private final String lockId;
        private final LockTimeoutListener listener;

        public LockDetails(long timeoutTime, String lockId, LockTimeoutListener listener) {
            this.timeoutTime = timeoutTime;
            this.lockId = lockId;
            this.listener = listener;
        }

        public LockTimeoutListener getListener() {
            return listener;
        }

        public String getLockId() {
            return lockId;
        }

        public long getTimeoutTime() {
            return timeoutTime;
        }
    }
}