public function getDatasetMetaData($datasetName) {
        $datasetName = StringHelper::trim($datasetName);

        $metamodel = data_controller_get_metamodel();

        $dataset = $metamodel->getDataset($datasetName);
        if (!$dataset->isComplete()) {
            $callcontext = $this->prepareCallContext();

            MetaModelFactory::getInstance()->startGlobalModification();
            try {
                RequestChainFactory::getInstance()->initializeChain()->loadDatasetMetaData(
                    $this->getDataSourceQueryHandlerByDataset($dataset), $callcontext, $dataset);

                $dataset->markAsComplete();
            }
            catch (Exception $e) {
                MetaModelFactory::getInstance()->finishGlobalModification(FALSE);
                throw $e;
            }
            MetaModelFactory::getInstance()->finishGlobalModification(TRUE);
        }

        return $dataset;
    }
    /**
     * @param DataControllerCallContext $callcontext
     * @param DatasetMetaData $dataset
     * @param DatasetStorageObserver[] $observers
     * @throws Exception
     */
    protected function disableDatasetStorage(DataControllerCallContext $callcontext, DatasetMetaData $dataset, array $observers = NULL) {
        MetaModelFactory::getInstance()->startGlobalModification();
        try {
            $transaction = db_transaction();
            try {
                $dataset->used = FALSE;

                if (isset($observers)) {
                    foreach ($observers as $observer) {
                        $observer->disableDataset($callcontext, $dataset);
                    }
                }
            }
            catch (Exception $e) {
                $transaction->rollback();
                throw $e;
            }
        }
        catch (Exception $e) {
            MetaModelFactory::getInstance()->finishGlobalModification(FALSE);
            throw $e;
        }
        MetaModelFactory::getInstance()->finishGlobalModification(TRUE);
    }
    protected function update(Import\ImportStream $stream, Import\ImportContext $context) {
        $datasets = $stream->get('datasets');
        if (empty($datasets)) {
            return;
        }

        gd_datasource_set_active($context->get('datasourceName'));
        $metamodel = data_controller_get_metamodel();

        $environment_metamodel = data_controller_get_environment_metamodel();
        $datasource = $environment_metamodel->getDataSource($context->get('datasourceName'));

        foreach ( $datasets as $dataset ) {
            $existingDataset = GD_DatasetMetaModelLoaderHelper::findDatasetByUUID($metamodel->datasets, $dataset->uuid);
            if ( !$existingDataset ) {

                // map for re-linking dependent objects
                $dataset->originalName = $dataset->name;

                // create new name
                $newDatasetName = GD_NamingConvention::generateDatasetName();
                $dataset->name = $newDatasetName;
                $dataset->source = $newDatasetName;
                $dataset->datasourceName = $datasource->name;
            } else {
                // map for re-linking dependent objects
                $dataset->originalName = $dataset->name;

                $dataset->name = $existingDataset->name;
                $dataset->source = $existingDataset->source;
                $dataset->datasourceName = $existingDataset->datasourceName;
            }
        }

        // prepare dataset columns for import
        $this->prepareColumns($datasets);

        // prepares the metadata object, has to be of type RecordMetaData
        foreach ( $datasets as $key => $dataset ) {
            $metadata = new DatasetMetaData();
            $metadata->initializeFrom($dataset);
            $datasets[$key] = $metadata;
        }

        // ensure datasets are created in order to satisfy dependencies
        usort($datasets, array(new ReferencedDatasetComparator(), 'compare'));

        foreach ( $datasets as $dataset ) {
            $existingDataset = GD_DatasetMetaModelLoaderHelper::findDatasetByUUID($metamodel->datasets, $dataset->uuid);
            if ($existingDataset) {
                gd_data_controller_ddl_modify_dataset($dataset);
            } else {
                MetaModelFactory::getInstance()->startGlobalModification();
                try {
                    $transaction = db_transaction();
                    try {
                        gd_data_controller_ddl_create_dataset($dataset);
                    } catch (Exception $e) {
                        $transaction->rollback();
                        throw $e;
                    }
                } catch (Exception $e) {
                    MetaModelFactory::getInstance()->finishGlobalModification(false);
                    throw $e;
                }
                MetaModelFactory::getInstance()->finishGlobalModification(true);
            }
        }

        $stream->set('datasets',$datasets);
    }
    public static function prepareReference(MetaModel $metamodel, $referenceNode, array $referencePointNodes = NULL) {
        $referencePoints = $lookupReferencePoints = $interlookupReferences = NULL;

        // loading reference points
        $referencePointIndex = 0;
        while (TRUE) {
            $point_nid = get_node_field_int_value($referenceNode, 'field_reference_point', $referencePointIndex, 'nid');
            if (!isset($point_nid)) {
                break;
            }

            $referencePointNode = $referencePointNodes[$point_nid];

            $datasetName = get_node_field_value($referencePointNode, 'field_ref_point_dataset_sysname', 0, 'value', TRUE);
            $dataset = $metamodel->findDataset($datasetName);
            if (isset($dataset)) {
                $referencePoint = new DatasetReferencePoint();
                $lookupReferencePoint = new DatasetReferencePoint();

                $loader = MetaModelFactory::getInstance()->getLoader($dataset->loaderName);

                $cube = $metamodel->getCube($dataset->name);
                $referenceDatasetName = $cube->factsDatasetName;

                // preparing list of columns
                $referencePointColumnIndex = 0;
                while (TRUE) {
                    $columnName = get_node_field_value($referencePointNode, 'field_ref_point_column_sysname', $referencePointColumnIndex);
                    if (isset($columnName) || ($referencePointColumnIndex === 0)) {
                        $referencePointColumn = $referencePoint->initiateColumn();
                        $referencePointColumn->datasetName = $referenceDatasetName;
                        $referencePoint->registerColumnInstance($referencePointColumn);
                        if (isset($columnName)) {
                            $referencePointColumn->columnName = $columnName;
                        }

                        $interlookupLookupReferencePointColumn = $lookupReferencePoint->initiateColumn();
                        $interlookupLookupReferencePointColumn->datasetName = $referenceDatasetName;
                        $interlookupLookupReferencePointColumn->columnName = $referencePointColumn->columnName;
                        ReferenceMetaModelLoaderHelper::adjustReferencePointColumn($loader, $metamodel, $interlookupLookupReferencePointColumn);
                        if (!$interlookupLookupReferencePointColumn->isShared()) {
                            $interlookupReferences[$referencePointColumnIndex][$referencePointIndex] = $interlookupLookupReferencePointColumn;
                        }

                        $lookupReferencePointColumn = clone $interlookupLookupReferencePointColumn;
                        $lookupReferencePointColumn->columnName = NULL;
                        $lookupReferencePoint->registerColumnInstance($lookupReferencePointColumn);
                    }
                    if (!isset($columnName)) {
                        break;
                    }

                    $referencePointColumnIndex++;
                }

                $referencePoints[$referencePointIndex] = $referencePoint;
                $lookupReferencePoints[$referencePointIndex] = $lookupReferencePoint;
            }

            $referencePointIndex++;
        }

        $referencePointCount = count($referencePoints);
        if ($referencePointCount == 0) {
            return;
        }

        // checking if we need to add references between lookup reference point columns (second reference point in each reference)
        if (isset($interlookupReferences)) {
            // creating separate references for each reference point
            foreach ($referencePoints as $referencePointIndex => $referencePoint) {
                $lookupReferencePoint = $lookupReferencePoints[$referencePointIndex];

                $reference = new DatasetReference();
                $reference->name = get_node_field_value($referenceNode, 'field_reference_sysname', 0, 'value', TRUE) . '_rp' . $referencePointIndex;

                $reference->registerPointInstance($referencePoint);
                $reference->registerPointInstance($lookupReferencePoint);
                $metamodel->registerReference($reference);
            }

            // linking lookup reference point columns
            foreach ($interlookupReferences as $columnIndex => $interlookupReferencePointColumns) {
                if (count($interlookupReferencePointColumns) < $referencePointCount) {
                    throw new UnsupportedOperationException(t('All reference point columns with the same reference point column index have to be non-shared'));
                }

                $interLookupReferenceName = get_node_field_value($referenceNode, 'field_reference_sysname', 0, 'value', TRUE) . '_rpci' . $columnIndex;
                foreach ($interlookupReferencePointColumns as $interlookupReferencePointColumn) {
                    $metamodel->registerSimpleReferencePoint(
                        $interLookupReferenceName,
                        $interlookupReferencePointColumn->datasetName, $interlookupReferencePointColumn->columnName);
                }
            }
        }
        else {
            // checking that all lookup reference points are the same
            $masterLookupReferencePoint = NULL;
            foreach ($lookupReferencePoints as $lookupReferencePoint) {
                if (isset($masterLookupReferencePoint)) {
                    if (!$masterLookupReferencePoint->equals($lookupReferencePoint)) {
                        throw new UnsupportedOperationException(t('Unlinkable lookup reference points are not the same'));
                    }
                }
                else {
                    $masterLookupReferencePoint = $lookupReferencePoint;
                }
            }

            // combining all reference points into one reference
            $reference = new DatasetReference();
            $reference->name = get_node_field_value($referenceNode, 'field_reference_sysname', 0, 'value', TRUE);
            foreach ($referencePoints as $referencePointIndex => $referencePoint) {
                $lookupReferencePoint = $lookupReferencePoints[$referencePointIndex];

                $reference->registerPointInstance($referencePoint);
                $reference->registerPointInstance($lookupReferencePoint);
            }
            $metamodel->registerReference($reference);
        }
    }
    /**
     * @param DataControllerCallContext $callcontext
     * @param DatasetMetaData $originalDataset
     * @param DatasetMetaData $modifiedDataset
     * @param DatasetStorageObserver[] $observers
     * @throws Exception
     */
    protected function updateProperties(DataControllerCallContext $callcontext, DatasetMetaData $originalDataset, DatasetMetaData $modifiedDataset, array $observers = NULL) {
        $justPersistedColumns = NULL;
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->newIncludedColumns);
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->restoredColumns);
        ArrayHelper::merge($justPersistedColumns, $callcontext->changeAction->updatedDataTypeIncludedColumns);

        $columns = $justPersistedColumns;
        ArrayHelper::merge($columns, $callcontext->changeAction->updatedColumns);
        if ($callcontext->changeAction->isDatasetUpdated || isset($columns) || $callcontext->changeAction->isKeyUpdated) {
            MetaModelFactory::getInstance()->startGlobalModification();
            try {
                $transaction = db_transaction();
                try {
                    if (isset($columns)) {
                        foreach ($columns as $column) {
                            if (isset($justPersistedColumns[$column->name])) {
                                $column->used = TRUE;
                            }

                            if (isset($callcontext->changeAction->updatedColumns[$column->name])) {
                                $modifiedColumn = $modifiedDataset->getColumn($column->name);

                                $column->publicName = $modifiedColumn->publicName;
                                $column->description = $modifiedColumn->description;
                                $column->source = $modifiedColumn->source;
                                $column->key = $modifiedColumn->key;
                            }

                            if (isset($observers)) {
                                foreach ($observers as $observer) {
                                    $observer->updateColumn($callcontext, $originalDataset, $column->name);
                                }
                            }
                        }
                    }

                    if ($callcontext->changeAction->isDatasetUpdated) {
                        $originalDataset->publicName = $modifiedDataset->publicName;
                        $originalDataset->description = $modifiedDataset->description;
                        $originalDataset->initializeSourceFrom($modifiedDataset->source, TRUE);
                        $originalDataset->initializeAliasesFrom($modifiedDataset->aliases, TRUE);

                        if (isset($observers)) {
                            foreach ($observers as $observer) {
                                $observer->updateDataset($callcontext, $originalDataset);
                            }
                        }
                    }

                    if ($callcontext->changeAction->isKeyUpdated) {
                        $modifiedDatasetKeyColumnNames = $modifiedDataset->findKeyColumnNames();
                        if (isset($modifiedDatasetKeyColumnNames)) {
                            $this->executeDatasetUpdateOperations(
                                $callcontext,
                                $originalDataset,
                                array(new CreateDatasetKeyOperation()));
                        }
                    }
                }
                catch (Exception $e) {
                    $transaction->rollback();
                    throw $e;
                }
            }
            catch (Exception $e) {
                MetaModelFactory::getInstance()->finishGlobalModification(FALSE);
                throw $e;
            }
            MetaModelFactory::getInstance()->finishGlobalModification(TRUE);
        }
    }
    /**
     * @param DataControllerCallContext $callcontext
     * @param DatasetMetaData $dataset
     * @param DatasetStorageObserver[] $observers
     * @throws Exception
     */
    protected function dropDatasetStorage(DataControllerCallContext $callcontext, DatasetMetaData $dataset, array $observers = NULL) {
        MetaModelFactory::getInstance()->startGlobalModification();
        try {
            $transaction = db_transaction();
            try {
                if (isset($observers)) {
                    foreach ($observers as $observer) {
                        $observer->unregisterDataset($callcontext, $dataset, DatasetStorageObserver::STAGE__BEFORE);
                    }
                }

                // dropping physical storage of the dataset
                $request = new DatasetStorageRequest($dataset->name);
                LogHelper::log_debug($request);
                $this->datasourceStructureHandler->dropDatasetStorage($callcontext, $request);

                $dataset->used = FALSE;

                if (isset($observers)) {
                    foreach ($observers as $observer) {
                        $observer->unregisterDataset($callcontext, $dataset, DatasetStorageObserver::STAGE__AFTER);
                    }
                }
            }
            catch (Exception $e) {
                $transaction->rollback();
                throw $e;
            }
        }
        catch (Exception $e) {
            MetaModelFactory::getInstance()->finishGlobalModification(FALSE);
            throw $e;
        }
        MetaModelFactory::getInstance()->finishGlobalModification(TRUE);
    }