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

com.gooddata.sdk.service.project.model.ModelService Maven / Gradle / Ivy

There is a newer version: 3.11.1+api3
Show newest version
/*
 * Copyright (C) 2004-2019, GoodData(R) Corporation. All rights reserved.
 * This source code is licensed under the BSD-style license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */
package com.gooddata.sdk.service.project.model;

import com.gooddata.sdk.common.GoodDataRestException;
import com.gooddata.sdk.model.gdc.AsyncTask;
import com.gooddata.sdk.model.gdc.TaskStatus;
import com.gooddata.sdk.model.project.Project;
import com.gooddata.sdk.model.project.model.DiffRequest;
import com.gooddata.sdk.model.project.model.MaqlDdl;
import com.gooddata.sdk.model.project.model.MaqlDdlLinks;
import com.gooddata.sdk.model.project.model.ModelDiff;
import com.gooddata.sdk.service.*;
import com.gooddata.sdk.service.dataset.DatasetService;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.io.Reader;
import java.util.Collection;
import java.util.LinkedList;

import static com.gooddata.sdk.common.util.Validate.notNullState;
import static com.gooddata.sdk.model.project.model.ModelDiff.UpdateScript;
import static com.gooddata.sdk.common.util.Validate.noNullElements;
import static com.gooddata.sdk.common.util.Validate.notNull;
import static java.util.Arrays.asList;

/**
 * Service for manipulating with project model
 */
public class ModelService extends AbstractService {

    public ModelService(final RestTemplate restTemplate, final GoodDataSettings settings) {
        super(restTemplate, settings);
    }

    private FutureResult getProjectModelDiff(Project project, DiffRequest diffRequest) {
        notNull(project, "project");
        notNull(project.getId(), "project.id");
        notNull(diffRequest, "diffRequest");
        try {
            final AsyncTask asyncTask = restTemplate
                    .postForObject(DiffRequest.URI, diffRequest, AsyncTask.class, project.getId());
            return new PollResult<>(this, new SimplePollHandler(notNullState(asyncTask, "model diff task").getUri(), ModelDiff.class) {
                @Override
                public void handlePollException(final GoodDataRestException e) {
                    throw new ModelException("Unable to get project model diff", e);
                }
            });
        } catch (GoodDataRestException | RestClientException e) {
            throw new ModelException("Unable to get project model diff", e);
        }
    }

    public FutureResult getProjectModelDiff(Project project, String targetModel) {
        notNull(project, "project");
        notNull(targetModel, "targetModel");
        return getProjectModelDiff(project, new DiffRequest(targetModel));
    }

    public FutureResult getProjectModelDiff(Project project, Reader targetModel) {
        notNull(project, "project");
        notNull(targetModel, "targetModel");
        try {
            return getProjectModelDiff(project, FileCopyUtils.copyToString(targetModel));
        } catch (IOException e) {
            throw new ModelException("Can't read target model", e);
        }
    }

    /**
     * Update project model with the MAQL script from given ModelDiff with the least side-effects
     * (see {@link ModelDiff#getUpdateMaql()}).
     *
     * @param project   project to be updated
     * @param modelDiff difference of model to be applied into the project
     * @return poll result
     */
    public FutureResult updateProjectModel(Project project, ModelDiff modelDiff) {
        notNull(modelDiff, "modelDiff");
        return updateProjectModel(project, modelDiff.getUpdateMaql());
    }

    /**
     * Update project model with the given update script (MAQL).
     *
     * @param project      project to be updated
     * @param updateScript update script to be executed in the project
     * @return poll result
     */
    public FutureResult updateProjectModel(Project project, UpdateScript updateScript) {
        notNull(updateScript, "updateScript");
        return updateProjectModel(project, updateScript.getMaqlChunks());
    }

    /**
     * Update project model with the given update script(s) (MAQL). For data manipulation use
     * {@link ModelService#updateProjectModel}.
     *
     * @param project project to be updated
     * @param maqlDdl update script to be executed in the project
     * @return poll result
     *
     * @see DatasetService#updateProjectData
     */
    public FutureResult updateProjectModel(final Project project, final String... maqlDdl) {
        return updateProjectModel(project, asList(maqlDdl));
    }

    /**
     * Update project model with the given update script(s) (MAQL).
     *
     * @param project project to be updated
     * @param maqlDdl update script to be executed in the project
     * @return poll result
     *
     * @see DatasetService#updateProjectData
     */
    public FutureResult updateProjectModel(final Project project, final Collection maqlDdl) {
        notNull(project, "project");
        notNull(project.getId(), "project.id");
        noNullElements(maqlDdl, "maqlDdl");
        if (maqlDdl.isEmpty()) {
            throw new IllegalArgumentException("MAQL DDL string(s) should be given");
        }
        return new PollResult<>(this, new AbstractPollHandlerBase(MaqlDdlLinks.class, Void.class) {

            private final String projectId = project.getId();
            private final LinkedList maqlChunks = new LinkedList<>(maqlDdl);
            private String pollUri;

            {
                executeNextMaqlChunk();
            }

            /**
             * @return true if polling should finish, false otherwise
             */
            private boolean executeNextMaqlChunk() {
                if (maqlChunks.isEmpty()) {
                    return true;
                }
                try {
                    final MaqlDdlLinks links = restTemplate.postForObject(MaqlDdl.URI, new MaqlDdl(maqlChunks.poll()),
                        MaqlDdlLinks.class, projectId);
                    this.pollUri = notNullState(links, "maqlDdlLinks").getStatusUri();
                } catch (GoodDataRestException | RestClientException e) {
                    throw new ModelException("Unable to update project model", e);
                }
                return false;
            }

            @Override
            public String getPollingUri() {
                return pollUri;
            }

            @Override
            public boolean isFinished(final ClientHttpResponse response) throws IOException {
                if (!super.isFinished(response)) {
                    return false;
                }
                final TaskStatus maqlDdlTaskStatus = extractData(response, TaskStatus.class);
                if (!maqlDdlTaskStatus.isSuccess()) {
                    throw new ModelException("Unable to update project model: " + maqlDdlTaskStatus.getMessages());
                }
                return executeNextMaqlChunk();
            }

            @Override
            public void handlePollResult(MaqlDdlLinks pollResult) {
                setResult(null);
            }

            @Override
            public void handlePollException(final GoodDataRestException e) {
                throw new ModelException("Unable to update project model", e);
            }
        });
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy