org.apache.falcon.cli.FalconEntityCLI.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.falcon.cli.FalconEntityCLI.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.falcon.cli;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.StringUtils;
import org.apache.falcon.ResponseHelper;
import org.apache.falcon.client.FalconCLIException;
import org.apache.falcon.client.FalconClient;
import org.apache.falcon.entity.v0.EntityType;
import org.apache.falcon.entity.v0.SchemaHelper;
import org.apache.falcon.resource.EntityList;
import org.apache.falcon.resource.FeedLookupResult;
import org.apache.falcon.resource.SchedulableEntityInstanceResult;

import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * Entity extension to Falcon Command Line Interface - wraps the RESTful API for entities.
 */
public class FalconEntityCLI extends FalconCLI {

    private static final String SUBMIT_OPT = "submit";
    private static final String UPDATE_OPT = "update";
    private static final String DELETE_OPT = "delete";
    private static final String SUBMIT_AND_SCHEDULE_OPT = "submitAndSchedule";
    private static final String VALIDATE_OPT = "validate";
    private static final String DEFINITION_OPT = "definition";
    public static final String SLA_MISS_ALERT_OPT = "slaAlert";

    private static final String LOOKUP_OPT = "lookup";
    private static final String PATH_OPT = "path";
    private static final String TOUCH_OPT = "touch";
    private static final String PROPS_OPT = "properties";
    private static final String FIELDS_OPT = "fields";
    private static final String TAGS_OPT = "tags";
    private static final String NUM_INSTANCES_OPT = "numInstances";
    private static final String NAMESEQ_OPT = "nameseq";
    private static final String TAGKEYS_OPT = "tagkeys";

    public FalconEntityCLI() throws Exception {
        super();
    }

    public Options createEntityOptions() {

        Options entityOptions = new Options();

        Option submit = new Option(SUBMIT_OPT, false, "Submits an entity xml to Falcon");
        Option update = new Option(UPDATE_OPT, false, "Updates an existing entity xml");
        Option schedule = new Option(SCHEDULE_OPT, false, "Schedules a submited entity in Falcon");
        Option suspend = new Option(SUSPEND_OPT, false, "Suspends a running entity in Falcon");
        Option resume = new Option(RESUME_OPT, false, "Resumes a suspended entity in Falcon");
        Option delete = new Option(DELETE_OPT, false,
                "Deletes an entity in Falcon, and kills its instance from workflow engine");
        Option submitAndSchedule = new Option(SUBMIT_AND_SCHEDULE_OPT, false,
                "Submits and entity to Falcon and schedules it immediately");
        Option validate = new Option(VALIDATE_OPT, false, "Validates an entity based on the entity type");
        Option status = new Option(STATUS_OPT, false, "Gets the status of entity");
        Option definition = new Option(DEFINITION_OPT, false, "Gets the Definition of entity");
        Option dependency = new Option(DEPENDENCY_OPT, false, "Gets the dependencies of entity");
        Option list = new Option(LIST_OPT, false, "List entities registered for a type");
        Option lookup = new Option(LOOKUP_OPT, false, "Lookup a feed given its instance's path");
        Option slaAlert = new Option(SLA_MISS_ALERT_OPT, false, "Get missing feed instances which missed SLA");
        Option entitySummary = new Option(SUMMARY_OPT, false, "Get summary of instances for list of entities");
        Option touch = new Option(TOUCH_OPT, false,
                "Force update the entity in workflow engine(even without any changes to entity)");

        OptionGroup group = new OptionGroup();
        group.addOption(submit);
        group.addOption(update);
        group.addOption(schedule);
        group.addOption(suspend);
        group.addOption(resume);
        group.addOption(delete);
        group.addOption(submitAndSchedule);
        group.addOption(validate);
        group.addOption(status);
        group.addOption(definition);
        group.addOption(dependency);
        group.addOption(list);
        group.addOption(lookup);
        group.addOption(slaAlert);
        group.addOption(entitySummary);
        group.addOption(touch);

        Option url = new Option(URL_OPTION, true, "Falcon URL");
        Option entityType = new Option(TYPE_OPT, true, "Entity type, can be cluster, feed or process xml");
        Option filePath = new Option(FILE_PATH_OPT, true, "Path to entity xml file");
        Option entityName = new Option(ENTITY_NAME_OPT, true, "Entity type, can be cluster, feed or process xml");
        Option start = new Option(START_OPT, true, "Start time is optional for summary");
        Option end = new Option(END_OPT, true, "End time is optional for summary");
        Option colo = new Option(COLO_OPT, true, "Colo name");
        Option cluster = new Option(CLUSTER_OPT, true, "Cluster name");
        colo.setRequired(false);
        Option fields = new Option(FIELDS_OPT, true, "Entity fields to show for a request");
        Option filterBy = new Option(FILTER_BY_OPT, true, "Filter returned entities by the specified status");
        Option filterTags = new Option(TAGS_OPT, true, "Filter returned entities by the specified tags");
        Option nameSubsequence = new Option(NAMESEQ_OPT, true, "Subsequence of entity name");
        Option tagKeywords = new Option(TAGKEYS_OPT, true, "Keywords in tags");
        Option orderBy = new Option(ORDER_BY_OPT, true, "Order returned entities by this field");
        Option sortOrder = new Option(SORT_ORDER_OPT, true, "asc or desc order for results");
        Option offset = new Option(OFFSET_OPT, true, "Start returning entities from this offset");
        Option numResults = new Option(NUM_RESULTS_OPT, true, "Number of results to return per request");
        Option numInstances = new Option(NUM_INSTANCES_OPT, true,
                "Number of instances to return per entity summary request");
        Option path = new Option(PATH_OPT, true, "Path for a feed's instance");
        Option skipDryRun = new Option(SKIPDRYRUN_OPT, false, "skip dry run in workflow engine");
        Option doAs = new Option(DO_AS_OPT, true, "doAs user");
        Option userProps = new Option(PROPS_OPT, true, "User supplied comma separated key value properties");
        Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout");

        entityOptions.addOption(url);
        entityOptions.addOption(path);
        entityOptions.addOptionGroup(group);
        entityOptions.addOption(entityType);
        entityOptions.addOption(entityName);
        entityOptions.addOption(filePath);
        entityOptions.addOption(colo);
        entityOptions.addOption(cluster);
        entityOptions.addOption(start);
        entityOptions.addOption(end);
        entityOptions.addOption(fields);
        entityOptions.addOption(filterBy);
        entityOptions.addOption(filterTags);
        entityOptions.addOption(nameSubsequence);
        entityOptions.addOption(tagKeywords);
        entityOptions.addOption(orderBy);
        entityOptions.addOption(sortOrder);
        entityOptions.addOption(offset);
        entityOptions.addOption(numResults);
        entityOptions.addOption(numInstances);
        entityOptions.addOption(skipDryRun);
        entityOptions.addOption(doAs);
        entityOptions.addOption(userProps);
        entityOptions.addOption(debug);

        return entityOptions;
    }

    public void entityCommand(CommandLine commandLine, FalconClient client) throws FalconCLIException, IOException {
        Set<String> optionsList = new HashSet<String>();
        for (Option option : commandLine.getOptions()) {
            optionsList.add(option.getOpt());
        }

        String result = null;
        String entityType = commandLine.getOptionValue(TYPE_OPT);
        String entityName = commandLine.getOptionValue(ENTITY_NAME_OPT);
        String filePath = commandLine.getOptionValue(FILE_PATH_OPT);
        String colo = commandLine.getOptionValue(COLO_OPT);
        colo = getColo(colo);
        String cluster = commandLine.getOptionValue(CLUSTER_OPT);
        String start = commandLine.getOptionValue(START_OPT);
        String end = commandLine.getOptionValue(END_OPT);
        String orderBy = commandLine.getOptionValue(ORDER_BY_OPT);
        String sortOrder = commandLine.getOptionValue(SORT_ORDER_OPT);
        String filterBy = commandLine.getOptionValue(FILTER_BY_OPT);
        String filterTags = commandLine.getOptionValue(TAGS_OPT);
        String nameSubsequence = commandLine.getOptionValue(NAMESEQ_OPT);
        String tagKeywords = commandLine.getOptionValue(TAGKEYS_OPT);
        String fields = commandLine.getOptionValue(FIELDS_OPT);
        String feedInstancePath = commandLine.getOptionValue(PATH_OPT);
        Integer offset = parseIntegerInput(commandLine.getOptionValue(OFFSET_OPT), 0, "offset");
        Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT), null, "numResults");
        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);

        Integer numInstances = parseIntegerInput(commandLine.getOptionValue(NUM_INSTANCES_OPT), 7, "numInstances");
        Boolean skipDryRun = null;
        if (optionsList.contains(SKIPDRYRUN_OPT)) {
            skipDryRun = true;
        }

        String userProps = commandLine.getOptionValue(PROPS_OPT);

        EntityType entityTypeEnum = null;
        if (optionsList.contains(LIST_OPT)) {
            if (entityType == null) {
                entityType = "";
            }
            if (StringUtils.isNotEmpty(entityType)) {
                String[] types = entityType.split(",");
                for (String type : types) {
                    EntityType.getEnum(type);
                }
            }
        } else {
            validateNotEmpty(entityType, TYPE_OPT);
            entityTypeEnum = EntityType.getEnum(entityType);
        }
        validateSortOrder(sortOrder);
        String entityAction = "entity";

        if (optionsList.contains(SLA_MISS_ALERT_OPT)) {
            validateNotEmpty(entityType, TYPE_OPT);
            validateNotEmpty(start, START_OPT);
            parseDateString(start);
            parseDateString(end);
            SchedulableEntityInstanceResult response = client.getFeedSlaMissPendingAlerts(entityType, entityName,
                    start, end, colo);
            result = ResponseHelper.getString(response);
        } else if (optionsList.contains(SUBMIT_OPT)) {
            validateNotEmpty(filePath, "file");
            validateColo(optionsList);
            result = client.submit(entityType, filePath, doAsUser).getMessage();
        } else if (optionsList.contains(LOOKUP_OPT)) {
            validateNotEmpty(feedInstancePath, PATH_OPT);
            FeedLookupResult resp = client.reverseLookUp(entityType, feedInstancePath, doAsUser);
            result = ResponseHelper.getString(resp);
        } else if (optionsList.contains(UPDATE_OPT)) {
            validateNotEmpty(filePath, "file");
            validateColo(optionsList);
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            result = client.update(entityType, entityName, filePath, skipDryRun, doAsUser).getMessage();
        } else if (optionsList.contains(SUBMIT_AND_SCHEDULE_OPT)) {
            validateNotEmpty(filePath, "file");
            validateColo(optionsList);
            result = client.submitAndSchedule(entityType, filePath, skipDryRun, doAsUser, userProps).getMessage();
        } else if (optionsList.contains(VALIDATE_OPT)) {
            validateNotEmpty(filePath, "file");
            validateColo(optionsList);
            result = client.validate(entityType, filePath, skipDryRun, doAsUser).getMessage();
        } else if (optionsList.contains(SCHEDULE_OPT)) {
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            colo = getColo(colo);
            result = client.schedule(entityTypeEnum, entityName, colo, skipDryRun, doAsUser, userProps)
                    .getMessage();
        } else if (optionsList.contains(SUSPEND_OPT)) {
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            colo = getColo(colo);
            result = client.suspend(entityTypeEnum, entityName, colo, doAsUser).getMessage();
        } else if (optionsList.contains(RESUME_OPT)) {
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            colo = getColo(colo);
            result = client.resume(entityTypeEnum, entityName, colo, doAsUser).getMessage();
        } else if (optionsList.contains(DELETE_OPT)) {
            validateColo(optionsList);
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            result = client.delete(entityTypeEnum, entityName, doAsUser).getMessage();
        } else if (optionsList.contains(STATUS_OPT)) {
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            colo = getColo(colo);
            result = client.getStatus(entityTypeEnum, entityName, colo, doAsUser).getMessage();
        } else if (optionsList.contains(DEFINITION_OPT)) {
            validateColo(optionsList);
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            result = client.getDefinition(entityType, entityName, doAsUser).toString();
        } else if (optionsList.contains(DEPENDENCY_OPT)) {
            validateColo(optionsList);
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            result = client.getDependency(entityType, entityName, doAsUser).toString();
        } else if (optionsList.contains(LIST_OPT)) {
            validateColo(optionsList);
            validateEntityFields(fields);
            validateOrderBy(orderBy, entityAction);
            validateFilterBy(filterBy, entityAction);
            EntityList entityList = client.getEntityList(entityType, fields, nameSubsequence, tagKeywords, filterBy,
                    filterTags, orderBy, sortOrder, offset, numResults, doAsUser);
            result = entityList != null ? entityList.toString() : "No entity of type (" + entityType + ") found.";
        } else if (optionsList.contains(SUMMARY_OPT)) {
            validateEntityTypeForSummary(entityType);
            validateNotEmpty(cluster, CLUSTER_OPT);
            validateEntityFields(fields);
            validateFilterBy(filterBy, entityAction);
            validateOrderBy(orderBy, entityAction);
            result = ResponseHelper.getString(client.getEntitySummary(entityType, cluster, start, end, fields,
                    filterBy, filterTags, orderBy, sortOrder, offset, numResults, numInstances, doAsUser));
        } else if (optionsList.contains(TOUCH_OPT)) {
            validateNotEmpty(entityName, ENTITY_NAME_OPT);
            colo = getColo(colo);
            result = client.touch(entityType, entityName, colo, skipDryRun, doAsUser).getMessage();
        } else if (optionsList.contains(HELP_CMD)) {
            OUT.get().println("Falcon Help");
        } else {
            throw new FalconCLIException("Invalid command");
        }
        OUT.get().println(result);
    }

    private void validateColo(Set<String> optionsList) throws FalconCLIException {
        if (optionsList.contains(COLO_OPT)) {
            throw new FalconCLIException("Invalid argument : " + COLO_OPT);
        }
    }

    private void validateEntityFields(String fields) throws FalconCLIException {
        if (StringUtils.isEmpty(fields)) {
            return;
        }
        String[] fieldsList = fields.split(",");
        for (String s : fieldsList) {
            try {
                EntityList.EntityFieldList.valueOf(s.toUpperCase());
            } catch (IllegalArgumentException ie) {
                throw new FalconCLIException("Invalid fields argument : " + FIELDS_OPT);
            }
        }
    }

    private Date parseDateString(String time) throws FalconCLIException {
        if (time != null && !time.isEmpty()) {
            try {
                return SchemaHelper.parseDateUTC(time);
            } catch (Exception e) {
                throw new FalconCLIException("Time " + time + " is not valid", e);
            }
        }
        return null;
    }

}