org.springframework.ide.eclipse.boot.dash.livexp.DisposingFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.ide.eclipse.boot.dash.livexp.DisposingFactory.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Pivotal, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Pivotal, Inc. - initial API and implementation
 *******************************************************************************/
package org.springframework.ide.eclipse.boot.dash.livexp;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.springsource.ide.eclipse.commons.livexp.core.DisposeListener;
import org.springsource.ide.eclipse.commons.livexp.core.LiveExpression;
import org.springsource.ide.eclipse.commons.livexp.core.ValueListener;
import org.springsource.ide.eclipse.commons.livexp.ui.Disposable;

import org.springsource.ide.eclipse.commons.livexp.core.ObservableSet;

import com.google.common.collect.ImmutableSet;

/**
 * A disposing factory creates objects of some type V based on some
 * parameter of type K. It guarantees that the same element is returned
 * when the same key is passed in as argument, provided that the
 * key is one of the currently 'validKeys'.
 * <p>
 * The factory is also responsible for monitoring the set of 'validKeys' and calling
 * the dispose method on the values associated with keys that are no longer
 * valid.
 *
 * @author Kris De Volder
 */
public abstract class DisposingFactory<K, V extends Disposable> implements Disposable {

    private ObservableSet<K> validKeys;
    private Map<K, V> cachedInstances = new HashMap<>();
    private ValueListener<ImmutableSet<K>> validKeyListener = null;

    public DisposingFactory(ObservableSet<K> validKeys) {
        this.validKeys = validKeys;
        validKeys.onDispose(new DisposeListener() {
            public void disposed(Disposable disposed) {
                DisposingFactory.this.dispose();
            }
        });
    }

    protected abstract V create(K key);

    public synchronized V createOrGet(K key) {
        ImmutableSet<K> valid = getValidKeys();
        if (valid.contains(key)) {
            enableValidKeyTracking();
            V instance = cachedInstances.get(key);
            if (instance == null) {
                instance = create(key);
                if (instance != null) {
                    cachedInstances.put(key, instance);
                }
            }
            return instance;
        }
        return null;
    }

    private void enableValidKeyTracking() {
        if (validKeyListener == null) {
            validKeys.addListener(validKeyListener = new ValueListener<ImmutableSet<K>>() {
                public void gotValue(LiveExpression<ImmutableSet<K>> exp, ImmutableSet<K> value) {
                    retainOnlyValidKeys();
                }
            });
        }

    }

    private ImmutableSet<K> getValidKeys() {
        if (validKeys != null) {
            return validKeys.getValues();
        }
        return ImmutableSet.of();
    }

    @Override
    public synchronized void dispose() {
        if (validKeys != null) {
            if (validKeyListener != null) {
                validKeys.removeListener(validKeyListener);
            }
            validKeys = null;
            retainOnlyValidKeys();
            cachedInstances = null;
        }
    }

    private synchronized void retainOnlyValidKeys() {
        if (cachedInstances != null) {
            ImmutableSet<K> valid = getValidKeys();
            Iterator<Entry<K, V>> iter = cachedInstances.entrySet().iterator();
            while (iter.hasNext()) {
                Entry<K, V> e = iter.next();
                K k = e.getKey();
                if (valid.contains(k)) {
                    //keep
                } else {
                    e.getValue().dispose();
                    iter.remove();
                }
            }
        }
    }

}