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

org.eobjects.metamodel.CompositeDataContext Maven / Gradle / Ivy

/**
 * eobjects.org MetaModel
 * Copyright (C) 2010 eobjects.org
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.eobjects.metamodel;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eobjects.metamodel.data.DataSet;
import org.eobjects.metamodel.query.FromItem;
import org.eobjects.metamodel.query.Query;
import org.eobjects.metamodel.schema.CompositeSchema;
import org.eobjects.metamodel.schema.Schema;
import org.eobjects.metamodel.schema.Table;
import org.eobjects.metamodel.util.Func;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * DataContext for composite datacontexts. Composite DataContexts wrap several
 * other datacontexts and makes cross-datastore querying possible.
 * 
 * @author Kasper Sørensen
 */
public class CompositeDataContext extends AbstractDataContext {

    private final static Logger logger = LoggerFactory.getLogger(CompositeDataContext.class);
    private Map _compositeSchemas = new HashMap();
    private DataContext[] _delegates;

    public CompositeDataContext(DataContext... delegates) {
        if (delegates == null) {
            throw new IllegalArgumentException("delegates cannot be null");
        }
        _delegates = delegates;
    }

    public CompositeDataContext(Collection delegates) {
        if (delegates == null) {
            throw new IllegalArgumentException("delegates cannot be null");
        }
        _delegates = delegates.toArray(new DataContext[delegates.size()]);
    }

    @Override
    public DataSet executeQuery(Query query) throws MetaModelException {
        // a set of all datacontexts involved
        Set dataContexts = new HashSet();

        // find all datacontexts involved, by investigating FROM items
        List items = query.getFromClause().getItems();
        for (FromItem item : items) {
            List tableFromItems = MetaModelHelper.getTableFromItems(item);
            for (FromItem fromItem : tableFromItems) {
                Table table = fromItem.getTable();

                DataContext dc = getDataContext(table);
                if (dc == null) {
                    throw new MetaModelException("Could not resolve child-datacontext for table: " + table);
                }
                dataContexts.add(dc);
            }
        }

        if (dataContexts.isEmpty()) {
            throw new MetaModelException("No suiting delegate DataContext to execute query: " + query);
        } else if (dataContexts.size() == 1) {
            Iterator it = dataContexts.iterator();
            assert it.hasNext();
            DataContext dc = it.next();
            return dc.executeQuery(query);
        } else {
            // we create a datacontext which can materialize tables from
            // separate datacontexts.
            final Func dataContextRetrievalFunction = new Func() {
                @Override
                public DataContext eval(Table table) {
                    return getDataContext(table);
                }
            };
            return new CompositeQueryDelegate(dataContextRetrievalFunction).executeQuery(query);
        }
    }

    private DataContext getDataContext(Table table) {
        DataContext result = null;
        if (table != null) {
            Schema schema = table.getSchema();

            if (schema != null) {
                for (DataContext dc : _delegates) {
                    Schema dcSchema = dc.getSchemaByName(schema.getName());
                    if (dcSchema != null) {

                        // first round = try with schema identity match
                        if (dcSchema == schema) {
                            logger.debug("DataContext for '{}' resolved (using identity) to: '{}'", table, dcSchema);
                            result = dc;
                            break;
                        }
                    }
                }

                if (result == null) {
                    for (DataContext dc : _delegates) {
                        Schema dcSchema = dc.getSchemaByName(schema.getName());
                        if (dcSchema != null) {
                            // second round = try with schema equals method
                            if (dcSchema.equals(schema)) {
                                logger.debug("DataContext for '{}' resolved (using equals) to: '{}'", table, dcSchema);
                                result = dc;
                                break;
                            }
                        }
                    }
                }
            }
        }

        if (result == null) {
            logger.warn("Couldn't resolve DataContext for {}", table);
        }
        return result;
    }

    @Override
    public String getDefaultSchemaName() throws MetaModelException {
        for (DataContext dc : _delegates) {
            Schema schema = dc.getDefaultSchema();
            if (schema != null) {
                return schema.getName();
            }
        }
        return null;
    }

    @Override
    public Schema getSchemaByNameInternal(String name) throws MetaModelException {
        CompositeSchema compositeSchema = _compositeSchemas.get(name);
        if (compositeSchema != null) {
            return compositeSchema;
        }
        List matchingSchemas = new ArrayList();
        for (DataContext dc : _delegates) {
            Schema schema = dc.getSchemaByName(name);
            if (schema != null) {
                matchingSchemas.add(schema);
            }
        }
        if (matchingSchemas.size() == 1) {
            return matchingSchemas.iterator().next();
        }
        if (matchingSchemas.size() > 1) {
            if (logger.isInfoEnabled()) {
                logger.info("Name-clash detected for Schema '{}'. Creating CompositeSchema.");
            }
            compositeSchema = new CompositeSchema(name, matchingSchemas);
            _compositeSchemas.put(name, compositeSchema);
            return compositeSchema;
        }
        return null;
    }

    @Override
    public String[] getSchemaNamesInternal() throws MetaModelException {
        Set set = new HashSet();
        for (DataContext dc : _delegates) {
            String[] schemaNames = dc.getSchemaNames();
            for (String name : schemaNames) {
                if (!MetaModelHelper.isInformationSchema(name)) {
                    // we skip information schemas, since they're anyways going
                    // to be incomplete and misleading.
                    set.add(name);
                }
            }
        }
        String[] result = set.toArray(new String[set.size()]);
        Arrays.sort(result);
        return result;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy