Package org.apache.mina.util

Source Code of org.apache.mina.util.ExpiringMap$Expirer

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*    http://www.apache.org/licenses/LICENSE-2.0
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/
package org.apache.mina.util;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
import edu.emory.mathcs.backport.java.util.concurrent.locks.ReadWriteLock;
import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* A map with expiration.
*
* @author The Apache Directory Project (mina-dev@directory.apache.org)
*/
public class ExpiringMap implements Map
{
    public static final int DEFAULT_TIME_TO_LIVE = 60;

    public static final int DEFAULT_EXPIRATION_INTERVAL = 1;

    private static volatile int expirerCount = 1;

    private final ConcurrentHashMap delegate;

    private final CopyOnWriteArrayList expirationListeners;

    private final Expirer expirer;

    public ExpiringMap()
    {
        this( DEFAULT_TIME_TO_LIVE, DEFAULT_EXPIRATION_INTERVAL );
    }

    public ExpiringMap( int timeToLive )
    {
        this( timeToLive, DEFAULT_EXPIRATION_INTERVAL );
    }

    public ExpiringMap( int timeToLive, int expirationInterval )
    {
        this( new ConcurrentHashMap(), new CopyOnWriteArrayList(), timeToLive, expirationInterval );
    }

    private ExpiringMap(
            ConcurrentHashMap delegate, CopyOnWriteArrayList expirationListeners,
            int timeToLive, int expirationInterval )
    {
        this.delegate = delegate;
        this.expirationListeners = expirationListeners;

        this.expirer = new Expirer();
        expirer.setTimeToLive( timeToLive );
        expirer.setExpirationInterval( expirationInterval );
    }

    public Object put( Object key, Object value )
    {
        return delegate.put( key, new ExpiringObject( key, value, System.currentTimeMillis() ) );
    }

    public Object get( Object key )
    {
        Object object = delegate.get( key );

        if( object != null )
        {
            ExpiringObject expObject = ( ExpiringObject ) object;
            expObject.setLastAccessTime( System.currentTimeMillis() );

            return expObject.getValue();
        }

        return object;
    }

    public Object remove( Object key )
    {
        return delegate.remove( key );
    }

    public boolean containsKey( Object key )
    {
        return delegate.containsKey( key );
    }

    public boolean containsValue( Object value )
    {
        return delegate.containsValue( value );
    }

    public int size()
    {
        return delegate.size();
    }

    public boolean isEmpty()
    {
        return delegate.isEmpty();
    }

    public void clear()
    {
        delegate.clear();
    }

    public int hashCode()
    {
        return delegate.hashCode();
    }

    public Set keySet()
    {
        return delegate.keySet();
    }

    public boolean equals( Object obj )
    {
        return delegate.equals( obj );
    }

    public void putAll( Map inMap )
    {
        synchronized( inMap )
        {
            Iterator inMapKeysIt = inMap.keySet().iterator();

            while( inMapKeysIt.hasNext() )
            {
                Object key = inMapKeysIt.next();
                Object value = inMap.get( key );

                if( value instanceof ExpiringObject )
                {
                    delegate.put( key, value );
                }
            }
        }
    }

    public Collection values()
    {
        return delegate.values();
    }

    public Set entrySet()
    {
        return delegate.entrySet();
    }

    public void addExpirationListener( ExpirationListener listener )
    {
        expirationListeners.add( listener );
    }

    public void removeExpirationListener( ExpirationListener listener )
    {
        expirationListeners.remove( listener );
    }
   
    public Expirer getExpirer()
    {
        return expirer;
    }

    public int getExpirationInterval()
    {
        return expirer.getExpirationInterval();
    }

    public int getTimeToLive()
    {
        return expirer.getTimeToLive();
    }

    public void setExpirationInterval( int expirationInterval )
    {
        expirer.setExpirationInterval( expirationInterval );
    }

    public void setTimeToLive( int timeToLive )
    {
        expirer.setTimeToLive( timeToLive );
    }

    private class ExpiringObject
    {
        private Object key;

        private Object value;

        private long lastAccessTime;

        private ReadWriteLock lastAccessTimeLock = new ReentrantReadWriteLock();

        public ExpiringObject( Object key, Object value, long lastAccessTime )
        {
            if( value == null )
            {
                throw new IllegalArgumentException( "An expiring object cannot be null." );
            }

            this.key = key;
            this.value = value;
            this.lastAccessTime = lastAccessTime;
        }

        public long getLastAccessTime()
        {
            lastAccessTimeLock.readLock().lock();

            try
            {
                return lastAccessTime;
            }
            finally
            {
                lastAccessTimeLock.readLock().unlock();
            }
        }

        public void setLastAccessTime( long lastAccessTime )
        {
            lastAccessTimeLock.writeLock().lock();

            try
            {
                this.lastAccessTime = lastAccessTime;
            }
            finally
            {
                lastAccessTimeLock.writeLock().unlock();
            }
        }

        public Object getKey()
        {
            return key;
        }

        public Object getValue()
        {
            return value;
        }

        public boolean equals( Object obj )
        {
            return value.equals( obj );
        }

        public int hashCode()
        {
            return value.hashCode();
        }
    }

    public class Expirer implements Runnable
    {
        private ReadWriteLock stateLock = new ReentrantReadWriteLock();

        private long timeToLiveMillis;

        private long expirationIntervalMillis;

        private boolean running = false;

        private final Thread expirerThread;

        public Expirer()
        {
            expirerThread = new Thread( this, "ExpiringMapExpirer-" + ( expirerCount++ ) );
            expirerThread.setDaemon( true );
        }

        public void run()
        {
            while( running )
            {
                processExpires();

                try
                {
                    Thread.sleep( expirationIntervalMillis );
                }
                catch( InterruptedException e )
                {
                }
            }
        }

        private void processExpires()
        {
            long timeNow = System.currentTimeMillis();

            Iterator expiringObjectsIterator = delegate.values().iterator();

            while( expiringObjectsIterator.hasNext() )
            {
                ExpiringObject expObject = ( ExpiringObject ) expiringObjectsIterator.next();

                if( timeToLiveMillis <= 0 )
                    continue;

                long timeIdle = timeNow - expObject.getLastAccessTime();

                if( timeIdle >= timeToLiveMillis )
                {
                    delegate.remove( expObject.getKey() );

                    Iterator listenerIterator = expirationListeners.iterator();

                    while( listenerIterator.hasNext() )
                    {
                        ExpirationListener listener = ( ExpirationListener ) listenerIterator.next();

                        listener.expired( expObject.getValue() );
                    }
                }
            }
        }

        public void startExpiring()
        {
            stateLock.writeLock().lock();

            try
            {
                if( !running )
                {
                    running = true;
                    expirerThread.start();
                }
            }
            finally
            {
                stateLock.writeLock().unlock();
            }
        }

        public void startExpiringIfNotStarted()
        {
            stateLock.readLock().lock();
            try
            {
                if( running )
                {
                    return;
                }
            }
            finally
            {
                stateLock.readLock().unlock();
            }
           
            stateLock.writeLock().lock();
            try
            {
                if( !running )
                {
                    running = true;
                    expirerThread.start();
                }
            }
            finally
            {
                stateLock.writeLock().unlock();
            }
        }

        public void stopExpiring()
        {
            stateLock.writeLock().lock();

            try
            {
                if( running )
                {
                    running = false;
                    expirerThread.interrupt();
                }
            }
            finally
            {
                stateLock.writeLock().unlock();
            }
        }

        public boolean isRunning()
        {
            stateLock.readLock().lock();

            try
            {
                return running;
            }
            finally
            {
                stateLock.readLock().unlock();
            }
        }

        public int getTimeToLive()
        {
            stateLock.readLock().lock();

            try
            {
                return ( int ) timeToLiveMillis / 1000;
            }
            finally
            {
                stateLock.readLock().unlock();
            }
        }

        public void setTimeToLive( long timeToLive )
        {
            stateLock.writeLock().lock();

            try
            {
                this.timeToLiveMillis = timeToLive * 1000;
            }
            finally
            {
                stateLock.writeLock().unlock();
            }
        }

        public int getExpirationInterval()
        {
            stateLock.readLock().lock();

            try
            {
                return ( int ) expirationIntervalMillis / 1000;
            }
            finally
            {
                stateLock.readLock().unlock();
            }
        }

        public void setExpirationInterval( long expirationInterval )
        {
            stateLock.writeLock().lock();

            try
            {
                this.expirationIntervalMillis = expirationInterval * 1000;
            }
            finally
            {
                stateLock.writeLock().unlock();
            }
        }
    }
}
TOP

Related Classes of org.apache.mina.util.ExpiringMap$Expirer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.