Package com.dci.intellij.dbn.common.content

Source Code of com.dci.intellij.dbn.common.content.DynamicContentImpl

package com.dci.intellij.dbn.common.content;

import com.dci.intellij.dbn.common.content.dependency.ContentDependencyAdapter;
import com.dci.intellij.dbn.common.content.dependency.VoidContentDependencyAdapter;
import com.dci.intellij.dbn.common.content.loader.DynamicContentLoadException;
import com.dci.intellij.dbn.common.content.loader.DynamicContentLoader;
import com.dci.intellij.dbn.common.dispose.DisposerUtil;
import com.dci.intellij.dbn.common.filter.Filter;
import com.dci.intellij.dbn.common.thread.BackgroundTask;
import com.dci.intellij.dbn.common.util.CollectionUtil;
import com.dci.intellij.dbn.connection.ConnectionHandler;
import com.dci.intellij.dbn.connection.GenericDatabaseElement;
import com.intellij.openapi.progress.ProgressIndicator;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public abstract class DynamicContentImpl<T extends DynamicContentElement> implements DynamicContent<T> {
    public static final List EMPTY_LIST = new ArrayList(0);

    private final Object LOAD_LOCK = new Object();
    private final Object BACKGROUND_LOAD_LOCK = new Object();

    private long changeTimestamp = 0;
    private volatile boolean isLoading = false;
    private volatile boolean isLoadingInBackground = false;
    private volatile boolean isLoaded = false;
    private volatile boolean isDirty = false;
    private volatile boolean isDisposed = false;

    private GenericDatabaseElement parent;
    protected DynamicContentLoader<T> loader;
    protected ContentDependencyAdapter dependencyAdapter;
    private boolean indexed;
    private Map<String, T> index;
    private int filterHashCode = 0;

    protected List<T> elements = EMPTY_LIST;

    protected DynamicContentImpl(GenericDatabaseElement parent, DynamicContentLoader<T> loader, ContentDependencyAdapter dependencyAdapter, boolean indexed) {
        this.parent = parent;
        this.loader = loader;
        this.dependencyAdapter = dependencyAdapter;
        this.indexed = indexed;
    }

    public boolean accepts(T element) {
        Filter filter = getFilter();
        return filter == null || filter.accepts(element);
    }

    public abstract Filter getFilter();

    public GenericDatabaseElement getParent() {
        return parent;
    }

    public ConnectionHandler getConnectionHandler() {
        return parent == null ? null : parent.getConnectionHandler();
    }

    public DynamicContentLoader<T> getLoader() {
        return loader;
    }

    public ContentDependencyAdapter getDependencyAdapter() {
        return dependencyAdapter;
    }

    public long getChangeTimestamp() {
        return changeTimestamp;
    }

    public boolean isLoaded() {
        return isLoaded;
    }

    /**
     * The content can load
     */
    public boolean canLoadFast() {
        return dependencyAdapter.canLoadFast();
    }

    @Override
    public boolean isSubContent() {
        return getDependencyAdapter().isSubContent();
    }

    public boolean isLoading() {
        return isLoading;
    }

    public boolean isDirty() {
        if (isDirty || dependencyAdapter.isDirty()) {
            return true;
        }

        Filter filter = getFilter();
        return filter == null ?
                filterHashCode != 0 :
                filterHashCode != filter.hashCode();

        //return isDirty /*|| (elements.size() > 0 && elements.get(0).isDisposed())*/;
    }

    public boolean isDisposed() {
        return isDisposed;
    }

    public void setDirty(boolean dirty) {
        isDirty = dirty;
    }

    public final void load(boolean force) {
        synchronized (LOAD_LOCK) {
            if (shouldLoad(force)) {
                isLoading = true;
                try {
                    performLoad();
                    isLoaded = true;
                } catch (InterruptedException e) {
                    setElements(EMPTY_LIST);
                    isDirty = true;
                } finally {
                    isLoading = false;
                    updateChangeTimestamp();
                }
            }
        }
    }

    public final void reload() {
        synchronized (LOAD_LOCK) {
            if (!isDisposed && !isLoading) {
                isLoading = true;
                try {
                    performReload();
                    isLoaded = true;
                } catch (InterruptedException e) {
                    setElements(EMPTY_LIST);
                    isDirty = true;
                } finally {
                    isLoading = false;
                    updateChangeTimestamp();
                }
            }
        }
    }

    @Override
    public final void loadInBackground(final boolean force) {
        synchronized (BACKGROUND_LOAD_LOCK) {
            if (!isLoadingInBackground && shouldLoad(force)) {
                isLoadingInBackground = true;
                new BackgroundTask(getProject(), "Loading data dictionary", true) {
                    public void execute(@NotNull ProgressIndicator progressIndicator) {
                        try {
                            DatabaseLoadMonitor.startBackgroundLoad();
                            load(force);
                        } finally {
                            DatabaseLoadMonitor.endBackgroundLoad();
                            isLoadingInBackground = false;
                        }
                    }
                }.start();
            }
        }
    }

    private void performLoad() throws InterruptedException {
        checkDisposed();
        dependencyAdapter.beforeLoad();
        checkDisposed();
        try {
            // mark first the dirty status since dirty dependencies may
            // become valid due to parallel background load
            isDirty = false;
            getLoader().loadContent(this, false);
        } catch (DynamicContentLoadException e) {
            isDirty = !e.isModelException();
        }
        checkDisposed();
        dependencyAdapter.afterLoad();
    }

    private void performReload() throws InterruptedException {
        checkDisposed();
        dependencyAdapter.beforeReload(this);
        checkDisposed();
        try {
            checkDisposed();
            getLoader().reloadContent(this);
        } catch (DynamicContentLoadException e) {
            isDirty = !e.isModelException();
        }
        checkDisposed();
        dependencyAdapter.afterReload(this);
    }

    public void updateChangeTimestamp() {
        changeTimestamp = System.currentTimeMillis();
    }


    /**
     * do whatever is needed after the content is loaded (e.g. refresh browser tree..)
     */
    public abstract void notifyChangeListeners();

    public void setElements(List<T> elements) {
        Filter filter = getFilter();
        filterHashCode = filter == null ? 0 : filter.hashCode();

        if (isDisposed || elements == null || elements.size() == 0) {
            elements = EMPTY_LIST;
            index = null;
        } else {
            Collections.sort(elements);

        }
        List<T> oldElements = this.elements;
        this.elements = elements;
        updateIndex();
        if (oldElements.size() != 0 || elements.size() != 0 ){
            notifyChangeListeners();
        }
        if (!dependencyAdapter.isSubContent() && oldElements.size() > 0 ) {
            DisposerUtil.dispose(oldElements);
        }
    }

    @NotNull
    public List<T> getElements() {
        if (isSubContent() || DatabaseLoadMonitor.isEnsureDataLoaded() || DatabaseLoadMonitor.isLoadingInBackground()) {
            load(false);
        } else{
            loadInBackground(false);
        }
        return elements;
    }

    protected void updateIndex() {
        if (indexed) {
            if (elements.size() > 0) {
                if (index == null)
                    index = new THashMap<String, T>(); else
                    index.clear();

                for (T element : elements) {
                    String name = element.getName().toUpperCase();
                    index.put(name, element);
                }
            } else {
                index = null;
            }
        }
    }

    public T getElement(String name) {
        if (name != null) {
            if (indexed && index != null) {
                return index.get(name.toUpperCase());
            } else {
                List<T> elements = getElements();
                for (T element : elements) {
                    if (element.getName().equalsIgnoreCase(name)) {
                        return element;
                    }
                }
            }
        }
        return null;
    }

    @Override
    @Nullable
    public List<T> getElements(String name) {
        List<T> elements = null;
        for (T element : getElements()) {
            if (element.getName().equalsIgnoreCase(name)) {
                if (elements == null) {
                    elements = new ArrayList<T>();
                }
                elements.add(element);
            }
        }
        return elements;
    }

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

    public boolean shouldLoad(boolean force) {
        return !(isLoading || isDisposed) && (force || !isLoaded || (isDirty() && dependencyAdapter.shouldLoadIfDirty()));
    }

    public void checkDisposed() throws InterruptedException {
        if (isDisposed) throw new InterruptedException();
    }

    public void dispose() {
        if (!isDisposed) {
            isDisposed = true;
            if (dependencyAdapter.isSubContent())
                elements.clear(); else
                DisposerUtil.dispose(elements);
            CollectionUtil.clearMap(index);
            dependencyAdapter.dispose();
            dependencyAdapter = VoidContentDependencyAdapter.INSTANCE;
            parent = null;
        }
    }
}
TOP

Related Classes of com.dci.intellij.dbn.common.content.DynamicContentImpl

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.