com.haulmont.cuba.web.gui.data.OptionsDsWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.web.gui.data.OptionsDsWrapper.java

Source

/*
 * Copyright (c) 2008-2016 Haulmont.
 *
 * Licensed 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 com.haulmont.cuba.web.gui.data;

import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.core.entity.Entity;
import com.haulmont.cuba.core.global.View;
import com.haulmont.cuba.gui.data.CollectionDatasource;
import com.haulmont.cuba.gui.data.Datasource;
import com.haulmont.cuba.gui.data.impl.CollectionDsHelper;
import com.haulmont.cuba.gui.data.impl.WeakDsListenerAdapter;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.ui.UI;
import org.apache.commons.lang.StringUtils;

import java.util.*;

/**
 * Uses any Object as his Id
 */
public class OptionsDsWrapper
        implements Container.Ordered, Container.ItemSetChangeNotifier, UnsubscribableDsWrapper {

    protected boolean autoRefresh;
    protected boolean ignoreListeners;
    protected boolean executeAutoRefreshInvalid = true;

    protected CollectionDatasource datasource;

    protected Datasource.StateChangeListener dsStateChangeListener;
    protected Datasource.ItemPropertyChangeListener dsItemPropertyChangeListener;
    protected CollectionDatasource.CollectionChangeListener cdsCollectionChangeListener;

    protected WeakDsListenerAdapter weakDsListenerAdapter;

    protected Collection<MetaPropertyPath> properties = new ArrayList<>();

    protected Map<Object, ItemWrapper> itemsCache = new HashMap<>();

    // lazily initialized listeners list
    protected List<ItemSetChangeListener> itemSetChangeListeners = null;

    public OptionsDsWrapper(CollectionDatasource datasource, boolean autoRefresh) {
        this(datasource, null, autoRefresh);
    }

    @SuppressWarnings("unchecked")
    public OptionsDsWrapper(CollectionDatasource datasource, Collection<MetaPropertyPath> properties,
            boolean autoRefresh) {
        this.datasource = datasource;
        this.autoRefresh = autoRefresh;

        final View view = datasource.getView();
        final MetaClass metaClass = datasource.getMetaClass();

        if (properties == null) {
            createProperties(view, metaClass);
        } else {
            this.properties.addAll(properties);
        }

        dsStateChangeListener = e -> itemsCache.clear();

        dsItemPropertyChangeListener = e -> {
            Item wrapper = getItemWrapper(e.getItem());

            // MetaProperty worked wrong with properties from inherited superclasses
            MetaPropertyPath metaPropertyPath = datasource.getMetaClass().getPropertyPath(e.getProperty());
            if (metaPropertyPath == null) {
                return;
            }
            Property itemProperty = wrapper.getItemProperty(metaPropertyPath);
            if (itemProperty instanceof PropertyWrapper) {
                ((PropertyWrapper) itemProperty).fireValueChangeEvent();
            }
        };

        cdsCollectionChangeListener = e -> {
            final boolean prevIgnoreListeners = ignoreListeners;
            try {
                itemsCache.clear();
                fireItemSetChanged();
            } finally {
                ignoreListeners = prevIgnoreListeners;
            }
        };

        weakDsListenerAdapter = new WeakDsListenerAdapter(datasource, dsItemPropertyChangeListener,
                dsStateChangeListener, cdsCollectionChangeListener);
        datasource.addCollectionChangeListener(weakDsListenerAdapter);
        datasource.addStateChangeListener(weakDsListenerAdapter);
        datasource.addItemPropertyChangeListener(weakDsListenerAdapter);
    }

    protected void createProperties(View view, MetaClass metaClass) {
        properties.addAll(CollectionDsHelper.createProperties(view, metaClass));
    }

    protected void fireItemSetChanged() {
        if (ignoreListeners) {
            return;
        }

        ignoreListeners = true;

        UI currentUi = UI.getCurrent();
        if (currentUi != null) {
            // ignore in tests
            if (currentUi.getConnectorTracker().isWritingResponse()) {
                // Suppress containerItemSetChange listeners during painting, undefined behavior may be occurred
                return;
            }
        }

        if (itemSetChangeListeners != null) {
            StaticItemSetChangeEvent event = new StaticItemSetChangeEvent(this);

            for (ItemSetChangeListener listener : itemSetChangeListeners) {
                listener.containerItemSetChange(event);
            }
        }

        ignoreListeners = false;
    }

    @Override
    public Item getItem(Object itemId) {
        CollectionDsHelper.autoRefreshInvalid(datasource, autoRefresh);

        Entity entity = (Entity) itemId;
        //noinspection unchecked
        final Object item = datasource.getItem(entity.getId());
        return item == null ? null : getItemWrapper(item);
    }

    protected Item getItemWrapper(Object item) {
        ItemWrapper wrapper = itemsCache.get(item);
        if (wrapper == null) {
            wrapper = createItemWrapper(item);
            itemsCache.put(item, wrapper);
        }

        return wrapper;
    }

    protected ItemWrapper createItemWrapper(Object item) {
        return new ItemWrapper(item, datasource.getMetaClass(), properties);
    }

    @Override
    public Collection getContainerPropertyIds() {
        return properties;
    }

    @Override
    public Collection getItemIds() {
        if (executeAutoRefreshInvalid) {
            if (UI.getCurrent().getConnectorTracker().isWritingResponse()) {
                try {
                    CollectionDsHelper.autoRefreshInvalid(datasource, autoRefresh);
                } catch (IllegalStateException ex) {
                    if (StringUtils.contains(ex.getMessage(),
                            "A connector should not be marked as dirty while a response is being written")) {
                        // explain exception
                        String message = String.format(
                                "Some datasource listener has modified the component while it is in rendering state. Please refresh datasource '%s' explicitly",
                                datasource.getId());
                        throw new IllegalStateException(message, ex);
                    }

                    throw ex;
                }
            } else {
                CollectionDsHelper.autoRefreshInvalid(datasource, autoRefresh);
            }
        }

        return datasource.getItems();
    }

    @Override
    public Property getContainerProperty(Object itemId, Object propertyId) {
        final Item item = getItem(itemId);
        return item == null ? null : item.getItemProperty(propertyId);
    }

    @Override
    public Class getType(Object propertyId) {
        MetaPropertyPath propertyPath = (MetaPropertyPath) propertyId;
        return propertyPath.getRangeJavaClass();
    }

    @Override
    public int size() {
        CollectionDsHelper.autoRefreshInvalid(datasource, autoRefresh);
        return datasource.size();
    }

    @Override
    public boolean containsId(Object itemId) {
        if (executeAutoRefreshInvalid) {
            CollectionDsHelper.autoRefreshInvalid(datasource, autoRefresh);
        }
        //noinspection unchecked
        return itemId != null && datasource.containsItem(((Entity) itemId).getId());
    }

    @Override
    public Item addItem(Object itemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Object addItem() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeItem(Object itemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean addContainerProperty(Object propertyId, Class type, Object defaultValue)
            throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
        //noinspection SuspiciousMethodCalls
        return this.properties.remove(propertyId);
    }

    @Override
    public boolean removeAllItems() throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public void addItemSetChangeListener(ItemSetChangeListener listener) {
        if (itemSetChangeListeners == null) {
            itemSetChangeListeners = new LinkedList<>();
        }

        itemSetChangeListeners.add(listener);
    }

    @Override
    public void addListener(ItemSetChangeListener listener) {
        addItemSetChangeListener(listener);
    }

    @Override
    public void removeItemSetChangeListener(ItemSetChangeListener listener) {
        if (itemSetChangeListeners != null) {
            itemSetChangeListeners.remove(listener);

            if (itemSetChangeListeners.isEmpty()) {
                itemSetChangeListeners = null;
            }
        }
    }

    @Override
    public void removeListener(ItemSetChangeListener listener) {
        removeItemSetChangeListener(listener);
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object nextItemId(Object itemId) {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).nextItemId(((Entity) itemId).getId());
            return datasource.getItem(id);
        }
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object prevItemId(Object itemId) {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).prevItemId(((Entity) itemId).getId());
            return datasource.getItem(id);
        }
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object firstItemId() {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).firstItemId();
            return datasource.getItem(id);
        }
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object lastItemId() {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).lastItemId();
            return datasource.getItem(id);
        }
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean isFirstId(Object itemId) {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).firstItemId();
            return Objects.equals(datasource.getItem(id), itemId);
        }
        throw new UnsupportedOperationException();
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean isLastId(Object itemId) {
        if (datasource instanceof CollectionDatasource.Ordered) {
            Object id = ((CollectionDatasource.Ordered) datasource).lastItemId();
            return Objects.equals(datasource.getItem(id), itemId);
        }
        throw new UnsupportedOperationException();
    }

    @Override
    public Object addItemAfter(Object previousItemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Item addItemAfter(Object previousItemId, Object newItemId) throws UnsupportedOperationException {
        throw new UnsupportedOperationException();
    }

    public boolean isAutoRefresh() {
        return autoRefresh;
    }

    public void setAutoRefresh(boolean autoRefresh) {
        this.autoRefresh = autoRefresh;
    }

    @Override
    public String toString() {
        return "{ds=" + (datasource == null ? "null" : datasource.getId() + "}");
    }

    @SuppressWarnings("unchecked")
    @Override
    public void unsubscribe() {
        this.datasource.removeCollectionChangeListener(weakDsListenerAdapter);
        this.datasource.removeItemPropertyChangeListener(weakDsListenerAdapter);
        this.datasource.removeStateChangeListener(weakDsListenerAdapter);

        weakDsListenerAdapter = null;
        datasource = null;
    }

    public void setExecuteAutoRefreshInvalid(boolean executeAutoRefreshInvalid) {
        this.executeAutoRefreshInvalid = executeAutoRefreshInvalid;
    }
}