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

org.openmdx.base.collection.WeakRegistry Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * ====================================================================
 * Project:     openMDX/Core, http://www.openmdx.org/
 * Description: Weak Registry
 * Owner:       OMEX AG, Switzerland, http://www.omex.ch
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Copyright (c) 2010-2018, OMEX AG, Switzerland
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * * Neither the name of the openMDX team nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------
 * 
 * This product includes software developed by other organizations as
 * listed in the NOTICE file.
 */
package org.openmdx.base.collection;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;


/**
 * Weak Registry
 */
public class WeakRegistry implements Registry {

    /**
     * Constructor 
     *
     * @param threadSafetyRequired tells whether concurrent access needs to be supported or not
     */
    public WeakRegistry(
        boolean threadSafetyRequired
    ) {
        this.delegate = Maps.newMap(threadSafetyRequired);
        this.queue = new ReferenceQueue<>();
    }
    
    /**
     * The concurrent map holding the cache's references
     */
    private Map> delegate;

    /**
     * The value reference queue
     */
    private ReferenceQueue queue;

    /**
     * The value collection
     */
    private final Set values = new AbstractSet() {

        /* (non-Javadoc)
         * @see java.util.AbstractCollection#iterator()
         */
        @Override
        public Iterator iterator(
        ) {
            return new ValueIterator(
                getDelegate().values().iterator()
            );
        }

        /* (non-Javadoc)
         * @see java.util.AbstractCollection#size()
         */
        @Override
        public int size() {
            return getDelegate().size();
        }
        
    };

    /**
     * Retrieve the delegate after evicting its stale entries if required
     * 
     * @return the thread-safe delegate
     */
    protected Map> getDelegate(
    ){
        assertOpen();
        if(this.queue.poll() != null){
            clearQueue();
            evictStaleEntries();
        }
        return this.delegate;
    }

    /**
     * Determines whether the registry is open or closed
     * 
     * @return true if the reogistry is open
     */
    private boolean isOpen(){
        return this.delegate != null;
    }
    
    /**
     * Assert that the registry is open
     * 
     * @throws IllegalStateException if the registry is already closed
     */
    private void assertOpen() {
        if(this.delegate == null) {
            throw new IllegalStateException("This registry is already closed");
        }
    }

    /**
     * Get rid of stale entries
     */
    private synchronized void evictStaleEntries() {
        for(
            Iterator> i = this.delegate.values().iterator();
            i.hasNext();
        ){
            if(i.next().get() == null) {
                i.remove();
            }
        }
    }


    /**
     * Clear the reference queue
     */
    private void clearQueue() {
        while(this.queue.poll() != null) {
            // Iterate as there is no clear() method
        }
    }
    
    /**
     * Clear the delegate
     */
    private void clearDelegate() {
        this.delegate.clear();
    }
    
    
    //------------------------------------------------------------------------
    // Implements Registry
    //------------------------------------------------------------------------

    /* (non-Javadoc)
     * @see org.openmdx.base.collection.Cache#clear()
     */
    @Override
    public void clear() {
        assertOpen();
        clearDelegate();
        clearQueue();
    }

    /* (non-Javadoc)
     * @see org.openmdx.base.collection.Registry#close()
     */
    @Override
    public synchronized void close() {
        if(isOpen()) {
            clearDelegate();
            this.delegate = null;
            clearQueue();
            this.queue = null;
        }
    }

    /* (non-Javadoc)
     * 
     * @see org.openmdx.base.collection.Cache#get(java.lang.Object)
     */
    @Override
    public V get(K key) {
        WeakReference v = getDelegate().get(key); 
        return v == null ? null : v.get();
    }

    /* (non-Javadoc)
     * @see org.openmdx.base.collection.Cache#remove(java.lang.Object)
     */
    @Override
    public V remove(K key) {
        WeakReference v = getDelegate().remove(key); 
        return v == null ? null : v.get();
    }

    /* (non-Javadoc)
     * @see org.openmdx.base.collection.Cache#putIfAbsent(java.lang.Object, java.lang.Object)
     */
    @Override
    public V putUnlessPresent(K key, V value) {
        WeakReference v = new WeakReference(value, this.queue);
        Map> delegate = getDelegate();
        WeakReference c = delegate.putIfAbsent(key, v);
        if(c == null) {
            return value;
        } else {
            V concurrent = c.get();
            if(concurrent == null) {
                delegate.put(key, v);
                return value;
            } else {
                return concurrent;
            }
        }
    }

    /* (non-Javadoc)
     * @see org.openmdx.base.collection.Cache#put(java.lang.Object, java.lang.Object)
     */
    @Override
    public V put(K key, V value) {
        WeakReference v = new WeakReference(value, this.queue);
        WeakReference c = getDelegate().put(key, v);
        return c == null ? null : c.get();
    }


    /**
     * Retrieve the objects managed by the cache
     * *
     * @return a collection with the objects managed by the cache
     * 
     * @throws IllegalStateException if the registry is already closed
     */
    @Override
    public Set values(
    ){
        assertOpen();
        return this.values;
    }
    
    
    //------------------------------------------------------------------------
    // Class ValueIterator
    //------------------------------------------------------------------------
    
    /**
     * Value Iterator
     */
    static class ValueIterator implements Iterator {
        
        /**
         * Constructor 
         *
         * @param delegate
         */
        public ValueIterator(
            Iterator> delegate
        ){
            this.delegate = delegate;
        }

        /**
         * The reference iterator
         */
        private final Iterator> delegate;
        
        /**
         * The prefetched value
         */
        private V next = null;
        
        /* (non-Javadoc)
         * @see java.util.Iterator#hasNext()
         */
        @Override
        public boolean hasNext() {
            while(this.next == null && this.delegate.hasNext()) {
                this.next = this.delegate.next().get();
            }
            return this.next != null;
        }

        /* (non-Javadoc)
         * @see java.util.Iterator#next()
         */
        @Override
        public V next() {
            if(hasNext()) {
                V next = this.next;
                this.next = null;
                return next;
            } else {
                throw new NoSuchElementException();
            }
        }

        /* (non-Javadoc)
         * @see java.util.Iterator#remove()
         */
       @Override
        public void remove() {
            this.delegate.remove();
        }
        
    }        

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy