org.apache.gobblin.service.FlowConfigResourceLocalHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.gobblin.service.FlowConfigResourceLocalHandler.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.gobblin.service;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;

import com.google.common.collect.Maps;
import com.linkedin.data.template.StringMap;
import com.linkedin.restli.common.ComplexResourceKey;
import com.linkedin.restli.common.EmptyRecord;
import com.linkedin.restli.common.HttpStatus;
import com.linkedin.restli.server.CreateResponse;
import com.linkedin.restli.server.UpdateResponse;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import org.apache.gobblin.config.ConfigBuilder;
import org.apache.gobblin.configuration.ConfigurationKeys;
import org.apache.gobblin.runtime.api.FlowSpec;
import org.apache.gobblin.runtime.api.SpecNotFoundException;
import org.apache.gobblin.runtime.spec_catalog.FlowCatalog;

/**
 * A {@link FlowConfigsResourceHandler} that handles Restli locally.
 */
@Slf4j
public class FlowConfigResourceLocalHandler implements FlowConfigsResourceHandler {
    @Getter
    private FlowCatalog flowCatalog;

    public FlowConfigResourceLocalHandler(FlowCatalog flowCatalog) {
        this.flowCatalog = flowCatalog;
    }

    /**
     * Get flow config
     */
    public FlowConfig getFlowConfig(FlowId flowId) throws FlowConfigLoggedException {
        log.info("[GAAS-REST] Get called with flowGroup {} flowName {}", flowId.getFlowGroup(),
                flowId.getFlowName());

        try {
            URI flowCatalogURI = new URI("gobblin-flow", null, "/", null, null);
            URI flowUri = new URI(flowCatalogURI.getScheme(), flowCatalogURI.getAuthority(),
                    "/" + flowId.getFlowGroup() + "/" + flowId.getFlowName(), null, null);
            FlowSpec spec = (FlowSpec) flowCatalog.getSpec(flowUri);
            FlowConfig flowConfig = new FlowConfig();
            Properties flowProps = spec.getConfigAsProperties();
            Schedule schedule = null;

            if (flowProps.containsKey(ConfigurationKeys.JOB_SCHEDULE_KEY)) {
                schedule = new Schedule();
                schedule.setCronSchedule(flowProps.getProperty(ConfigurationKeys.JOB_SCHEDULE_KEY));
            }
            if (flowProps.containsKey(ConfigurationKeys.JOB_TEMPLATE_PATH)) {
                flowConfig.setTemplateUris(flowProps.getProperty(ConfigurationKeys.JOB_TEMPLATE_PATH));
            } else if (spec.getTemplateURIs().isPresent()) {
                flowConfig.setTemplateUris(StringUtils.join(spec.getTemplateURIs().get(), ","));
            } else {
                flowConfig.setTemplateUris("NA");
            }
            if (schedule != null) {
                if (flowProps.containsKey(ConfigurationKeys.FLOW_RUN_IMMEDIATELY)) {
                    schedule.setRunImmediately(
                            Boolean.valueOf(flowProps.getProperty(ConfigurationKeys.FLOW_RUN_IMMEDIATELY)));
                }

                flowConfig.setSchedule(schedule);
            }

            // remove keys that were injected as part of flowSpec creation
            flowProps.remove(ConfigurationKeys.JOB_SCHEDULE_KEY);
            flowProps.remove(ConfigurationKeys.JOB_TEMPLATE_PATH);

            StringMap flowPropsAsStringMap = new StringMap();
            flowPropsAsStringMap.putAll(Maps.fromProperties(flowProps));

            return flowConfig
                    .setId(new FlowId().setFlowGroup(flowId.getFlowGroup()).setFlowName(flowId.getFlowName()))
                    .setProperties(flowPropsAsStringMap);
        } catch (URISyntaxException e) {
            throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST, "bad URI " + flowId.getFlowName(), e);
        } catch (SpecNotFoundException e) {
            throw new FlowConfigLoggedException(HttpStatus.S_404_NOT_FOUND,
                    "Flow requested does not exist: " + flowId.getFlowName(), null);
        }
    }

    /**
     * Add flowConfig locally and trigger all listeners iff @param triggerListener is set to true
     */
    public CreateResponse createFlowConfig(FlowConfig flowConfig, boolean triggerListener)
            throws FlowConfigLoggedException {
        log.info("[GAAS-REST] Create called with flowGroup " + flowConfig.getId().getFlowGroup() + " flowName "
                + flowConfig.getId().getFlowName());
        FlowSpec flowSpec = createFlowSpecForConfig(flowConfig);
        this.flowCatalog.put(flowSpec, triggerListener);
        return new CreateResponse(new ComplexResourceKey<>(flowConfig.getId(), new EmptyRecord()),
                HttpStatus.S_201_CREATED);
    }

    /**
     * Add flowConfig locally and trigger all listeners
     */
    public CreateResponse createFlowConfig(FlowConfig flowConfig) throws FlowConfigLoggedException {
        return this.createFlowConfig(flowConfig, true);
    }

    /**
     * Update flowConfig locally and trigger all listeners iff @param triggerListener is set to true
     */
    public UpdateResponse updateFlowConfig(FlowId flowId, FlowConfig flowConfig, boolean triggerListener) {
        log.info("[GAAS-REST] Update called with flowGroup {} flowName {}", flowId.getFlowGroup(),
                flowId.getFlowName());

        if (!flowId.getFlowGroup().equals(flowConfig.getId().getFlowGroup())
                || !flowId.getFlowName().equals(flowConfig.getId().getFlowName())) {
            throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST,
                    "flowName and flowGroup cannot be changed in update", null);
        }

        this.flowCatalog.put(createFlowSpecForConfig(flowConfig), triggerListener);
        return new UpdateResponse(HttpStatus.S_200_OK);
    }

    /**
     * Update flowConfig locally and trigger all listeners
     */
    public UpdateResponse updateFlowConfig(FlowId flowId, FlowConfig flowConfig) throws FlowConfigLoggedException {
        return updateFlowConfig(flowId, flowConfig, true);
    }

    /**
     * Delete flowConfig locally and trigger all listeners iff @param triggerListener is set to true
     */
    public UpdateResponse deleteFlowConfig(FlowId flowId, Properties header, boolean triggerListener)
            throws FlowConfigLoggedException {

        log.info("[GAAS-REST] Delete called with flowGroup {} flowName {}", flowId.getFlowGroup(),
                flowId.getFlowName());
        URI flowUri = null;

        try {
            flowUri = createFlowSpecUri(flowId);
            this.flowCatalog.remove(flowUri, header, triggerListener);
            return new UpdateResponse(HttpStatus.S_200_OK);
        } catch (URISyntaxException e) {
            throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST, "bad URI " + flowUri, e);
        }
    }

    /**
     * Delete flowConfig locally and trigger all listeners
     */
    public UpdateResponse deleteFlowConfig(FlowId flowId, Properties header) throws FlowConfigLoggedException {
        return deleteFlowConfig(flowId, header, true);
    }

    public static URI createFlowSpecUri(FlowId flowId) throws URISyntaxException {
        URI flowCatalogURI = new URI("gobblin-flow", null, "/", null, null);
        URI flowUri = new URI(flowCatalogURI.getScheme(), flowCatalogURI.getAuthority(),
                "/" + flowId.getFlowGroup() + "/" + flowId.getFlowName(), null, null);
        return flowUri;
    }

    /**
     * Build a {@link FlowSpec} from a {@link FlowConfig}
     * @param flowConfig flow configuration
     * @return {@link FlowSpec} created with attributes from flowConfig
     */
    public static FlowSpec createFlowSpecForConfig(FlowConfig flowConfig) {
        ConfigBuilder configBuilder = ConfigBuilder.create()
                .addPrimitive(ConfigurationKeys.FLOW_GROUP_KEY, flowConfig.getId().getFlowGroup())
                .addPrimitive(ConfigurationKeys.FLOW_NAME_KEY, flowConfig.getId().getFlowName());

        if (flowConfig.hasSchedule()) {
            Schedule schedule = flowConfig.getSchedule();
            configBuilder.addPrimitive(ConfigurationKeys.JOB_SCHEDULE_KEY, schedule.getCronSchedule());
            configBuilder.addPrimitive(ConfigurationKeys.FLOW_RUN_IMMEDIATELY, schedule.isRunImmediately());
        }

        Config config = configBuilder.build();
        Config configWithFallback = config.withFallback(ConfigFactory.parseMap(flowConfig.getProperties()));

        try {
            URI templateURI = new URI(flowConfig.getTemplateUris());
            return FlowSpec.builder().withConfig(configWithFallback).withTemplate(templateURI).build();
        } catch (URISyntaxException e) {
            throw new FlowConfigLoggedException(HttpStatus.S_400_BAD_REQUEST,
                    "bad URI " + flowConfig.getTemplateUris(), e);
        }
    }
}