com.haulmont.cuba.gui.xml.data.DsContextLoader.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.gui.xml.data.DsContextLoader.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.gui.xml.data;

import com.haulmont.bali.util.Dom4j;
import com.haulmont.bali.util.ReflectionHelper;
import com.haulmont.chile.core.datatypes.Datatype;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.core.entity.KeyValueEntity;
import com.haulmont.cuba.core.global.AppBeans;
import com.haulmont.cuba.core.global.DevelopmentException;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.Scripting;
import com.haulmont.cuba.core.global.filter.QueryFilter;
import com.haulmont.cuba.gui.data.*;
import com.haulmont.cuba.gui.data.impl.*;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Element;

import javax.annotation.Nullable;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Objects;

public class DsContextLoader {

    protected DsBuilder builder;
    private DataSupplier dataservice;
    private Scripting scripting;
    private Metadata metadata;

    protected DsContextImplementation context;

    public DsContextLoader(DataSupplier dataservice) {
        this.dataservice = dataservice;
        this.scripting = AppBeans.get(Scripting.NAME);
        this.metadata = AppBeans.get(Metadata.NAME);
    }

    public DsContext loadDatasources(@Nullable Element element, @Nullable DsContext parent) {
        if (element == null) {
            context = new DsContextImpl(dataservice);
            if (parent != null)
                context.setParent(parent);
            return context;
        }

        String contextClass = element.attributeValue("class");
        if (StringUtils.isEmpty(contextClass)) {
            final Element contextClassElement = element.element("class");
            if (contextClassElement != null) {
                contextClass = contextClassElement.getText();
                if (StringUtils.isEmpty(contextClass)) {
                    throw new IllegalStateException("Can't find dsContext class name");
                }
                context = createDsContext(contextClass, contextClassElement);
            } else {
                context = new DsContextImpl(dataservice);
            }
        } else {
            context = createDsContext(contextClass, null);
        }
        if (parent != null) {
            context.setParent(parent);
        }

        builder = DsBuilder.create(context);

        //noinspection unchecked
        List<Element> elements = element.elements("datasource");
        for (Element ds : elements) {
            Datasource datasource = loadDatasource(ds);
            setLoadDynamicAttributes(ds, datasource);
        }

        //noinspection unchecked
        elements = element.elements("hierarchicalDatasource");
        for (Element ds : elements) {
            Datasource datasource = loadHierarchicalDatasource(ds);
            setLoadDynamicAttributes(ds, datasource);
        }

        //noinspection unchecked
        elements = element.elements("collectionDatasource");
        for (Element ds : elements) {
            CollectionDatasource datasource = loadCollectionDatasource(ds);
            setLoadDynamicAttributes(ds, datasource);
        }

        //noinspection unchecked
        elements = element.elements("groupDatasource");
        for (Element ds : elements) {
            Datasource datasource = loadGroupDatasource(ds);
            setLoadDynamicAttributes(ds, datasource);
        }

        //noinspection unchecked
        elements = element.elements("runtimePropsDatasource");
        for (Element ds : elements) {
            loadRuntimePropsDatasource(ds);
        }

        //noinspection unchecked
        elements = element.elements("valueCollectionDatasource");
        for (Element ds : elements) {
            loadValueCollectionDatasource(ds);
        }

        //noinspection unchecked
        elements = element.elements("valueGroupDatasource");
        for (Element ds : elements) {
            loadValueGroupDatasource(ds);
        }

        //noinspection unchecked
        elements = element.elements("valueHierarchicalDatasource");
        for (Element ds : elements) {
            loadValueHierarchicalDatasource(ds);
        }

        context.executeLazyTasks();

        return context;
    }

    protected void setLoadDynamicAttributes(Element element, Datasource datasource) {
        datasource.setLoadDynamicAttributes("true".equals(element.attributeValue("loadDynamicAttributes")));
    }

    protected DsContextImplementation createDsContext(String contextClass, Element element) {
        DsContextImplementation context;

        final Class<?> aClass = scripting.loadClass(contextClass);
        if (aClass == null)
            throw new IllegalStateException("DsContext class " + contextClass + " is not found");
        try {
            final Constructor<?> constructor = aClass.getConstructor(DataSupplier.class);
            context = (DsContextImplementation) constructor.newInstance(dataservice);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        return context;
    }

    protected Datasource loadHierarchicalDatasource(Element element) {
        MetaClass metaClass = loadMetaClass(element);
        if (metaClass == null)
            throw new DevelopmentException("'class' attribute is not set for the datasource");
        initCollectionDatasourceAttributes(element, metaClass);

        HierarchicalDatasource datasource = builder.setDsClass(getDatasourceClass(element))
                .buildHierarchicalDatasource();

        String hierarchyProperty = element.attributeValue("hierarchyProperty");
        if (!StringUtils.isEmpty(hierarchyProperty)) {
            datasource.setHierarchyPropertyName(hierarchyProperty);
        }

        if (datasource instanceof CollectionDatasource.Suspendable)
            ((CollectionDatasource.Suspendable) datasource).setSuspended(true);

        loadQuery(element, datasource);

        loadDatasources(element, datasource);

        return datasource;
    }

    @Nullable
    private Class<?> getDatasourceClass(Element element) {
        String datasourceClass = element.attributeValue("datasourceClass");
        if (StringUtils.isEmpty(datasourceClass)) {
            Element datasourceClassElement = element.element("datasourceClass");
            if (datasourceClassElement != null)
                datasourceClass = datasourceClassElement.getTextTrim();
        }
        if (StringUtils.isEmpty(datasourceClass)) {
            return null;
        } else {
            Class<?> aClass = scripting.loadClass(datasourceClass);
            if (aClass == null)
                throw new IllegalStateException("Datasource class " + datasourceClass + " is not found");
            return aClass;
        }
    }

    protected Datasource loadGroupDatasource(Element element) {
        MetaClass metaClass = loadMetaClass(element);
        if (metaClass == null)
            throw new DevelopmentException("'class' attribute is not set for the datasource");
        initCollectionDatasourceAttributes(element, metaClass);

        GroupDatasource datasource = builder.setDsClass(getDatasourceClass(element)).buildGroupDatasource();

        if (datasource instanceof CollectionDatasource.Suspendable)
            ((CollectionDatasource.Suspendable) datasource).setSuspended(true);

        loadQuery(element, datasource);

        loadDatasources(element, datasource);

        return datasource;
    }

    protected Datasource loadDatasource(Element element) {
        initDatasourceAttributes(element);

        Datasource datasource = builder.setDsClass(getDatasourceClass(element)).buildDatasource();

        // TODO implement ContextListeners
        //        String item = element.attributeValue("item");
        //        if (!StringUtils.isBlank(item)) {
        //            final ParametersHelper.ParameterInfo info = ParametersHelper.parse(item);
        //            context.registerListener(info, datasource);
        //        }

        loadDatasources(element, datasource);

        return datasource;
    }

    private void initDatasourceAttributes(Element element) {
        String id = getDatasourceId(element);
        MetaClass metaClass = loadMetaClass(element);
        String viewName = element.attributeValue("view");

        builder.reset().setMetaClass(metaClass).setId(id).setViewName(viewName)
                .setAllowCommit(getAllowCommit(element));
    }

    protected void loadDatasources(Element element, Datasource datasource) {
        //noinspection unchecked
        List<Element> elements = element.elements("datasource");
        for (Element ds : elements) {
            final String property = ds.attributeValue("property");
            loadDatasource(ds, datasource, property);
        }

        //noinspection unchecked
        elements = element.elements("collectionDatasource");
        for (Element ds : elements) {
            final String property = ds.attributeValue("property");
            loadCollectionDatasource(ds, datasource, property);
        }

        //noinspection unchecked
        elements = element.elements("groupDatasource");
        for (Element ds : elements) {
            final String property = ds.attributeValue("property");
            loadGroupDatasource(ds, datasource, property);
        }

        //noinspection unchecked
        elements = element.elements("hierarchicalDatasource");
        for (Element ds : elements) {
            final String property = ds.attributeValue("property");
            loadHierarchicalDatasource(ds, datasource, property);
        }

        //noinspection unchecked
        elements = element.elements("runtimePropsDatasource");
        for (Element ds : elements) {
            loadRuntimePropsDatasource(ds);
        }
    }

    private Datasource loadDatasource(Element element, Datasource ds, String property) {
        initPropertyDatasourceAttributes(element, ds, property);

        Datasource datasource = builder.buildDatasource();

        loadDatasources(element, datasource);

        return datasource;
    }

    private void initPropertyDatasourceAttributes(Element element, Datasource ds, String property) {
        String id = getDatasourceId(element);
        MetaClass metaClass = ds.getMetaClass();
        metaClass.getPropertyNN(property); // check property existense

        builder.reset().setMetaClass(metaClass).setId(id).setMaster(ds).setProperty(property)
                .setAllowCommit(getAllowCommit(element));
    }

    private Datasource loadCollectionDatasource(Element element, Datasource ds, String property) {
        initPropertyDatasourceAttributes(element, ds, property);

        CollectionDatasource datasource = builder.setDsClass(getDatasourceClass(element))
                .buildCollectionDatasource();

        loadDatasources(element, datasource);

        return datasource;
    }

    private Datasource loadHierarchicalDatasource(Element element, Datasource ds, String property) {
        initPropertyDatasourceAttributes(element, ds, property);

        HierarchicalDatasource datasource = builder.setDsClass(getDatasourceClass(element))
                .buildHierarchicalDatasource();

        String hierarchyProperty = element.attributeValue("hierarchyProperty");
        if (!StringUtils.isEmpty(hierarchyProperty)) {
            datasource.setHierarchyPropertyName(hierarchyProperty);
        }

        loadDatasources(element, datasource);

        return datasource;
    }

    private Datasource loadGroupDatasource(Element element, Datasource ds, String property) {
        initPropertyDatasourceAttributes(element, ds, property);

        GroupDatasource datasource = builder.setDsClass(getDatasourceClass(element)).buildGroupDatasource();

        loadDatasources(element, datasource);

        return datasource;
    }

    protected MetaClass loadMetaClass(Element element) {
        final String className = element.attributeValue("class");
        if (className == null)
            return null;

        final Class<?> aClass = ReflectionHelper.getClass(className);
        final MetaClass metaClass = metadata.getSession().getClass(aClass);

        if (metaClass == null)
            throw new IllegalStateException(String.format("Can't find metaClass '%s'", className));

        return metaClass;
    }

    protected CollectionDatasource loadCollectionDatasource(Element element) {
        MetaClass metaClass = loadMetaClass(element);
        if (metaClass == null)
            throw new DevelopmentException("'class' attribute is not set for the datasource");
        initCollectionDatasourceAttributes(element, metaClass);

        CollectionDatasource datasource = builder.setDsClass(getDatasourceClass(element))
                .buildCollectionDatasource();

        String maxResults = element.attributeValue("maxResults");
        if (!StringUtils.isEmpty(maxResults))
            datasource.setMaxResults(Integer.parseInt(maxResults));

        if (datasource instanceof CollectionDatasource.Suspendable)
            ((CollectionDatasource.Suspendable) datasource).setSuspended(true);

        loadQuery(element, datasource);

        loadDatasources(element, datasource);

        return datasource;
    }

    private void loadQuery(Element element, CollectionDatasource datasource) {
        Element queryElem = element.element("query");
        if (queryElem != null) {
            Element filterElem = queryElem.element("filter");

            String query = queryElem.getText();
            if (!StringUtils.isBlank(query)) {
                if (filterElem != null)
                    datasource.setQuery(query, new QueryFilter(filterElem));
                else
                    datasource.setQuery(query);
            }
        }
    }

    private void initCollectionDatasourceAttributes(Element element, MetaClass metaClass) {
        String id = getDatasourceId(element);
        String viewName = element.attributeValue("view");

        String deletion = element.attributeValue("softDeletion");
        boolean softDeletion = deletion == null || Boolean.parseBoolean(deletion);
        boolean cacheable = Boolean.parseBoolean(element.attributeValue("cacheable"));

        builder.reset().setMetaClass(metaClass).setId(id).setViewName(viewName).setSoftDeletion(softDeletion)
                .setCacheable(cacheable).setRefreshMode(getRefreshMode(element))
                .setMaxResults(getMaxResults(element)).setAllowCommit(getAllowCommit(element));
    }

    private int getMaxResults(Element element) {
        String maxResults = element.attributeValue("maxResults");
        return StringUtils.isEmpty(maxResults) ? 0 : Integer.parseInt(maxResults);
    }

    private CollectionDatasource.RefreshMode getRefreshMode(Element element) {
        final String refreshModeName = element.attributeValue("refreshMode");
        return StringUtils.isEmpty(refreshModeName) ? CollectionDatasource.RefreshMode.ALWAYS
                : CollectionDatasource.RefreshMode.valueOf(refreshModeName);
    }

    private boolean getAllowCommit(Element element) {
        final String allowCommitStr = element.attributeValue("allowCommit");
        return StringUtils.isEmpty(allowCommitStr) || Boolean.parseBoolean(allowCommitStr);
    }

    protected RuntimePropsDatasource loadRuntimePropsDatasource(Element element) {
        String id = getDatasourceId(element);
        MetaClass metaClass = loadMetaClass(element);

        String mainDsId = element.attributeValue("mainDs");
        if (mainDsId == null) {
            throw new IllegalStateException("RuntimePropsDs attributes not specified");
        }

        String categorizedEntityClassName = element.attributeValue("categorizedEntityClass");
        MetaClass categorizedEntityMetaClass = null;
        if (StringUtils.isNotBlank(categorizedEntityClassName)) {
            final Class<?> aClass = ReflectionHelper.getClass(categorizedEntityClassName);
            categorizedEntityMetaClass = metadata.getSession().getClass(aClass);
        }

        builder.reset().setMetaClass(metaClass).setId(id);

        RuntimePropsDatasource datasource = builder.buildRuntimePropsDatasource(mainDsId,
                categorizedEntityMetaClass);

        loadDatasources(element, datasource);
        return datasource;
    }

    private ValueCollectionDatasourceImpl loadValueCollectionDatasource(Element element) {
        String id = getDatasourceId(element);
        builder.reset().setMetaClass(metadata.getClassNN(KeyValueEntity.class)).setId(id);

        ValueCollectionDatasourceImpl datasource = builder.setDsClass(getDatasourceClass(element))
                .buildValuesCollectionDatasource();

        String maxResults = element.attributeValue("maxResults");
        if (!StringUtils.isEmpty(maxResults))
            datasource.setMaxResults(Integer.parseInt(maxResults));

        datasource.setSuspended(true);

        loadQuery(element, datasource);

        loadProperties(element, datasource);

        datasource.setStoreName(element.attributeValue("store"));

        return datasource;
    }

    private ValueGroupDatasourceImpl loadValueGroupDatasource(Element element) {
        String id = getDatasourceId(element);
        builder.reset().setMetaClass(metadata.getClassNN(KeyValueEntity.class)).setId(id);

        ValueGroupDatasourceImpl datasource = builder.setDsClass(getDatasourceClass(element))
                .buildValuesGroupDatasource();

        String maxResults = element.attributeValue("maxResults");
        if (!StringUtils.isEmpty(maxResults))
            datasource.setMaxResults(Integer.parseInt(maxResults));

        datasource.setSuspended(true);

        loadQuery(element, datasource);

        loadProperties(element, datasource);

        datasource.setStoreName(element.attributeValue("store"));

        return datasource;
    }

    private ValueHierarchicalDatasourceImpl loadValueHierarchicalDatasource(Element element) {
        String id = getDatasourceId(element);
        builder.reset().setMetaClass(metadata.getClassNN(KeyValueEntity.class)).setId(id);

        ValueHierarchicalDatasourceImpl datasource = builder.setDsClass(getDatasourceClass(element))
                .buildValuesHierarchicalDatasource();

        String maxResults = element.attributeValue("maxResults");
        if (!StringUtils.isEmpty(maxResults))
            datasource.setMaxResults(Integer.parseInt(maxResults));

        datasource.setSuspended(true);

        loadQuery(element, datasource);

        loadProperties(element, datasource);

        String hierarchyProperty = element.attributeValue("hierarchyProperty");
        if (!StringUtils.isEmpty(hierarchyProperty)) {
            datasource.setHierarchyPropertyName(hierarchyProperty);
        }

        datasource.setStoreName(element.attributeValue("store"));

        return datasource;
    }

    private void loadProperties(Element element, ValueDatasource datasource) {
        Element propsEl = element.element("properties");
        if (propsEl != null) {
            for (Element propEl : Dom4j.elements(propsEl)) {
                String name = propEl.attributeValue("name");
                String className = propEl.attributeValue("class");
                if (className != null) {
                    datasource.addProperty(name, ReflectionHelper.getClass(className));
                } else {
                    String typeName = propEl.attributeValue("datatype");
                    Datatype datatype = typeName == null ? Datatypes.getNN(String.class) : Datatypes.get(typeName);
                    datasource.addProperty(name, datatype);
                }
            }
            String idProperty = propsEl.attributeValue("idProperty");
            if (idProperty != null) {
                if (datasource.getMetaClass().getProperty(idProperty) == null)
                    throw new DevelopmentException(String.format("Property '%s' is not defined", idProperty));
                datasource.setIdName(idProperty);
            }
        }
    }

    protected String getDatasourceId(Element element) {
        String id = element.attributeValue("id");
        for (Datasource datasource : context.getAll()) {
            if (Objects.equals(datasource.getId(), id))
                throw new DevelopmentException("Duplicated datasource id: " + id);
        }
        return id;
    }
}