You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@falcon.apache.org by pe...@apache.org on 2016/04/13 17:39:58 UTC

[1/2] falcon git commit: FALCON-1895 Refactoring of FalconCLI and FalconClient

Repository: falcon
Updated Branches:
  refs/heads/master 3e22a77fe -> 6655e90a7


http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
deleted file mode 100644
index 7d0f2f6..0000000
--- a/client/src/main/java/org/apache/falcon/cli/FalconCLI.java
+++ /dev/null
@@ -1,318 +0,0 @@
-/**
- * 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 com.sun.jersey.api.client.ClientHandlerException;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.falcon.client.FalconCLIException;
-import org.apache.falcon.client.FalconClient;
-import org.apache.falcon.entity.v0.EntityType;
-import org.apache.falcon.resource.EntityList;
-import org.apache.falcon.resource.InstancesResult;
-import org.apache.falcon.resource.InstancesSummaryResult;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.util.Arrays;
-import java.util.Properties;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Falcon Command Line Interface - wraps the RESTful API.
- */
-public class FalconCLI {
-
-    public static final AtomicReference<PrintStream> ERR = new AtomicReference<PrintStream>(System.err);
-    public static final AtomicReference<PrintStream> OUT = new AtomicReference<PrintStream>(System.out);
-
-    public static final String ENV_FALCON_DEBUG = "FALCON_DEBUG";
-    public static final String DEBUG_OPTION = "debug";
-    public static final String URL_OPTION = "url";
-    private static final String FALCON_URL = "FALCON_URL";
-
-    public static final String ADMIN_CMD = "admin";
-    public static final String HELP_CMD = "help";
-    public static final String METADATA_CMD = "metadata";
-    public static final String ENTITY_CMD = "entity";
-    public static final String INSTANCE_CMD = "instance";
-
-    public static final String TYPE_OPT = "type";
-    public static final String COLO_OPT = "colo";
-    public static final String CLUSTER_OPT = "cluster";
-    public static final String FEED_OPT = "feed";
-    public static final String PROCESS_OPT = "process";
-    public static final String ENTITY_NAME_OPT = "name";
-    public static final String FILE_PATH_OPT = "file";
-    public static final String VERSION_OPT = "version";
-    public static final String SCHEDULE_OPT = "schedule";
-    public static final String SUSPEND_OPT = "suspend";
-    public static final String RESUME_OPT = "resume";
-    public static final String STATUS_OPT = "status";
-    public static final String SUMMARY_OPT = "summary";
-    public static final String DEPENDENCY_OPT = "dependency";
-    public static final String LIST_OPT = "list";
-    public static final String SKIPDRYRUN_OPT = "skipDryRun";
-    public static final String FILTER_BY_OPT = "filterBy";
-    public static final String ORDER_BY_OPT = "orderBy";
-    public static final String SORT_ORDER_OPT = "sortOrder";
-    public static final String OFFSET_OPT = "offset";
-    public static final String NUM_RESULTS_OPT = "numResults";
-    public static final String START_OPT = "start";
-    public static final String END_OPT = "end";
-    public static final String CURRENT_COLO = "current.colo";
-    public static final String CLIENT_PROPERTIES = "/client.properties";
-    public static final String DO_AS_OPT = "doAs";
-
-    private final Properties clientProperties;
-
-    public FalconCLI() throws Exception {
-        clientProperties = getClientProperties();
-    }
-
-    /**
-     * Entry point for the Falcon CLI when invoked from the command line. Upon
-     * completion this method exits the JVM with '0' (success) or '-1'
-     * (failure).
-     *
-     * @param args options and arguments for the Falcon CLI.
-     */
-    public static void main(final String[] args) throws Exception {
-        System.exit(new FalconCLI().run(args));
-    }
-
-    // TODO help and headers
-    private static final String[] FALCON_HELP = { "the env variable '" + FALCON_URL
-                                                          + "' is used as default value for the '-" + URL_OPTION
-                                                          + "' option",
-                                                  "custom headers for Falcon web services can be specified using '-D"
-                                                          + FalconClient.WS_HEADER_PREFIX + "NAME=VALUE'", };
-    /**
-     * Run a CLI programmatically.
-     * <p/>
-     * It does not exit the JVM.
-     * <p/>
-     * A CLI instance can be used only once.
-     *
-     * @param args options and arguments for the Oozie CLI.
-     * @return '0' (success), '-1' (failure).
-     */
-    public synchronized int run(final String[] args) throws Exception {
-
-        CLIParser parser = new CLIParser("falcon", FALCON_HELP);
-
-        FalconAdminCLI adminCLI = new FalconAdminCLI();
-        FalconEntityCLI entityCLI = new FalconEntityCLI();
-        FalconInstanceCLI instanceCLI = new FalconInstanceCLI();
-        FalconMetadataCLI metadataCLI = new FalconMetadataCLI();
-
-        parser.addCommand(ADMIN_CMD, "", "admin operations", adminCLI.createAdminOptions(), true);
-        parser.addCommand(HELP_CMD, "", "display usage", new Options(), false);
-        parser.addCommand(ENTITY_CMD, "",
-                "Entity operations like submit, suspend, resume, delete, status, definition, submitAndSchedule",
-                entityCLI.createEntityOptions(), false);
-        parser.addCommand(INSTANCE_CMD, "",
-                "Process instances operations like running, status, kill, suspend, resume, rerun, logs",
-                instanceCLI.createInstanceOptions(), false);
-        parser.addCommand(METADATA_CMD, "", "Metadata operations like list, relations",
-                metadataCLI.createMetadataOptions(), true);
-        parser.addCommand(VERSION_OPT, "", "show client version", new Options(), false);
-
-        try {
-            CLIParser.Command command = parser.parse(args);
-            int exitValue = 0;
-            if (command.getName().equals(HELP_CMD)) {
-                parser.showHelp();
-            } else {
-                CommandLine commandLine = command.getCommandLine();
-                String falconUrl = getFalconEndpoint(commandLine);
-                FalconClient client = new FalconClient(falconUrl, clientProperties);
-
-                setDebugMode(client, commandLine.hasOption(DEBUG_OPTION));
-                if (command.getName().equals(ADMIN_CMD)) {
-                    exitValue = adminCLI.adminCommand(commandLine, client, falconUrl);
-                } else if (command.getName().equals(ENTITY_CMD)) {
-                    entityCLI.entityCommand(commandLine, client);
-                } else if (command.getName().equals(INSTANCE_CMD)) {
-                    instanceCLI.instanceCommand(commandLine, client);
-                } else if (command.getName().equals(METADATA_CMD)) {
-                    metadataCLI.metadataCommand(commandLine, client);
-                }
-            }
-            return exitValue;
-        } catch (ParseException ex) {
-            ERR.get().println("Invalid sub-command: " + ex.getMessage());
-            ERR.get().println();
-            ERR.get().println(parser.shortHelp());
-            ERR.get().println("Stacktrace:");
-            ex.printStackTrace();
-            return -1;
-        } catch (ClientHandlerException ex) {
-            ERR.get().print("Unable to connect to Falcon server, "
-                    + "please check if the URL is correct and Falcon server is up and running\n");
-            ERR.get().println("Stacktrace:");
-            ex.printStackTrace();
-            return -1;
-        } catch (FalconCLIException e) {
-            ERR.get().println("ERROR: " + e.getMessage());
-            return -1;
-        } catch (Exception ex) {
-            ERR.get().println("Stacktrace:");
-            ex.printStackTrace();
-            return -1;
-        }
-    }
-
-    protected Integer parseIntegerInput(String optionValue, Integer defaultVal, String optionName)
-        throws FalconCLIException {
-        Integer integer = defaultVal;
-        if (optionValue != null) {
-            try {
-                return Integer.parseInt(optionValue);
-            } catch (NumberFormatException e) {
-                throw new FalconCLIException("Input value provided for queryParam \""+ optionName
-                        +"\" is not a valid Integer");
-            }
-        }
-        return integer;
-    }
-
-    protected void validateEntityTypeForSummary(String type) throws FalconCLIException {
-        EntityType entityType = EntityType.getEnum(type);
-        if (!entityType.isSchedulable()) {
-            throw new FalconCLIException("Invalid entity type " + entityType
-                    + " for EntitySummary API. Valid options are feed or process");
-        }
-    }
-
-    protected void validateNotEmpty(String paramVal, String paramName) throws FalconCLIException {
-        if (StringUtils.isBlank(paramVal)) {
-            throw new FalconCLIException("Missing argument : " + paramName);
-        }
-    }
-
-    protected void validateSortOrder(String sortOrder) throws FalconCLIException {
-        if (!StringUtils.isBlank(sortOrder)) {
-            if (!sortOrder.equalsIgnoreCase("asc") && !sortOrder.equalsIgnoreCase("desc")) {
-                throw new FalconCLIException("Value for param sortOrder should be \"asc\" or \"desc\". It is  : "
-                        + sortOrder);
-            }
-        }
-    }
-
-    protected String getColo(String colo) throws FalconCLIException, IOException {
-        if (colo == null) {
-            Properties prop = getClientProperties();
-            colo = prop.getProperty(CURRENT_COLO, "*");
-        }
-        return colo;
-    }
-
-    protected void validateFilterBy(String filterBy, String filterType) throws FalconCLIException {
-        if (StringUtils.isEmpty(filterBy)) {
-            return;
-        }
-        String[] filterSplits = filterBy.split(",");
-        for (String s : filterSplits) {
-            String[] tempKeyVal = s.split(":", 2);
-            try {
-                if (filterType.equals("entity")) {
-                    EntityList.EntityFilterByFields.valueOf(tempKeyVal[0].toUpperCase());
-                } else if (filterType.equals("instance")) {
-                    InstancesResult.InstanceFilterFields.valueOf(tempKeyVal[0].toUpperCase());
-                }else if (filterType.equals("summary")) {
-                    InstancesSummaryResult.InstanceSummaryFilterFields.valueOf(tempKeyVal[0].toUpperCase());
-                } else {
-                    throw new IllegalArgumentException("Invalid API call: filterType is not valid");
-                }
-            } catch (IllegalArgumentException ie) {
-                throw new FalconCLIException("Invalid filterBy argument : " + tempKeyVal[0] + " in : " + s);
-            }
-        }
-    }
-
-    protected void validateOrderBy(String orderBy, String action) throws FalconCLIException {
-        if (StringUtils.isBlank(orderBy)) {
-            return;
-        }
-        if (action.equals("instance")) {
-            if (Arrays.asList(new String[]{"status", "cluster", "starttime", "endtime"})
-                .contains(orderBy.toLowerCase())) {
-                return;
-            }
-        } else if (action.equals("entity")) {
-            if (Arrays.asList(new String[] {"type", "name"}).contains(orderBy.toLowerCase())) {
-                return;
-            }
-        } else if (action.equals("summary")) {
-            if (Arrays.asList(new String[]{"cluster"})
-                    .contains(orderBy.toLowerCase())) {
-                return;
-            }
-        }
-        throw new FalconCLIException("Invalid orderBy argument : " + orderBy);
-    }
-
-    protected String getFalconEndpoint(CommandLine commandLine) throws FalconCLIException, IOException {
-        String url = commandLine.getOptionValue(URL_OPTION);
-        if (url == null) {
-            url = System.getenv(FALCON_URL);
-        }
-        if (url == null) {
-            if (clientProperties.containsKey("falcon.url")) {
-                url = clientProperties.getProperty("falcon.url");
-            }
-        }
-        if (url == null) {
-            throw new FalconCLIException("Failed to get falcon url from cmdline, or environment or client properties");
-        }
-
-        return url;
-    }
-
-    private void setDebugMode(FalconClient client, boolean debugOpt) {
-        String debug = System.getenv(ENV_FALCON_DEBUG);
-        if (debugOpt) {  // CLI argument "-debug" used
-            client.setDebugMode(true);
-        } else if (StringUtils.isNotBlank(debug)) {
-            System.out.println(ENV_FALCON_DEBUG + ": " + debug);
-            if (debug.trim().toLowerCase().equals("true")) {
-                client.setDebugMode(true);
-            }
-        }
-    }
-
-    private Properties getClientProperties() throws IOException {
-        InputStream inputStream = null;
-        try {
-            inputStream = FalconCLI.class.getResourceAsStream(CLIENT_PROPERTIES);
-            Properties prop = new Properties();
-            if (inputStream != null) {
-                prop.load(inputStream);
-            }
-            return prop;
-        } finally {
-            IOUtils.closeQuietly(inputStream);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
deleted file mode 100644
index 6f9d620..0000000
--- a/client/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/**
- * 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";
-    private static final String SHOWSCHEDULER_OPT = "showScheduler";
-
-    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 showScheduler = new Option(SHOWSCHEDULER_OPT, false, "To return the scheduler "
-                + "on which the entity is scheduled.");
-        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);
-        entityOptions.addOption(showScheduler);
-
-        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);
-        boolean showScheduler = false;
-        if (optionsList.contains(SHOWSCHEDULER_OPT)) {
-            showScheduler = true;
-        }
-
-        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, showScheduler).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;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
deleted file mode 100644
index 544bda8..0000000
--- a/client/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/**
- * 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.falcon.LifeCycle;
-import org.apache.falcon.ResponseHelper;
-import org.apache.falcon.client.FalconCLIException;
-import org.apache.falcon.client.FalconClient;
-import org.apache.falcon.resource.InstanceDependencyResult;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * Instance extension to Falcon Command Line Interface - wraps the RESTful API for instances.
- */
-public class FalconInstanceCLI extends FalconCLI {
-
-    private static final String FORCE_RERUN_FLAG = "force";
-    private static final String INSTANCE_TIME_OPT = "instanceTime";
-    private static final String RUNNING_OPT = "running";
-    private static final String KILL_OPT = "kill";
-    private static final String RERUN_OPT = "rerun";
-    private static final String LOG_OPT = "logs";
-    private static final String ALL_ATTEMPTS = "allAttempts";
-    private static final String RUNID_OPT = "runid";
-    private static final String CLUSTERS_OPT = "clusters";
-    private static final String SOURCECLUSTER_OPT = "sourceClusters";
-    private static final String LIFECYCLE_OPT = "lifecycle";
-    private static final String PARARMS_OPT = "params";
-    private static final String LISTING_OPT = "listing";
-    private static final String TRIAGE_OPT = "triage";
-
-    public FalconInstanceCLI() throws Exception {
-        super();
-    }
-
-    public Options createInstanceOptions() {
-
-        Options instanceOptions = new Options();
-
-        Option running = new Option(RUNNING_OPT, false,
-                "Gets running process instances for a given process");
-        Option list = new Option(LIST_OPT, false,
-                "Gets all instances for a given process in the range start time and optional end time");
-        Option status = new Option(STATUS_OPT, false,
-                "Gets status of process instances for a given process in the range start time and optional end time");
-        Option summary = new Option(SUMMARY_OPT, false,
-                "Gets summary of instances for a given process in the range start time and optional end time");
-        Option kill = new Option(KILL_OPT, false,
-                "Kills active process instances for a given process in the range start time and optional end time");
-        Option suspend = new Option(SUSPEND_OPT, false,
-                "Suspends active process instances for a given process in the range start time and optional end time");
-        Option resume = new Option(RESUME_OPT, false,
-                "Resumes suspended process instances for a given process "
-                        + "in the range start time and optional end time");
-        Option rerun = new Option(RERUN_OPT, false,
-                "Reruns process instances for a given process in the range start time and "
-                        + "optional end time and overrides properties present in job.properties file");
-        Option logs = new Option(LOG_OPT, false,
-                "Logs print the logs for process instances for a given process in "
-                        + "the range start time and optional end time");
-        Option params = new Option(PARARMS_OPT, false,
-                "Displays the workflow parameters for a given instance of specified nominal time"
-                        + "start time represents nominal time and end time is not considered");
-        Option listing = new Option(LISTING_OPT, false,
-                "Displays feed listing and their status between a start and end time range.");
-        Option dependency = new Option(DEPENDENCY_OPT, false,
-                "Displays dependent instances for a specified instance.");
-        Option triage = new Option(TRIAGE_OPT, false,
-                "Triage a feed or process instance and find the failures in it's lineage.");
-
-        OptionGroup group = new OptionGroup();
-        group.addOption(running);
-        group.addOption(list);
-        group.addOption(status);
-        group.addOption(summary);
-        group.addOption(kill);
-        group.addOption(resume);
-        group.addOption(suspend);
-        group.addOption(resume);
-        group.addOption(rerun);
-        group.addOption(logs);
-        group.addOption(params);
-        group.addOption(listing);
-        group.addOption(dependency);
-        group.addOption(triage);
-
-        Option url = new Option(URL_OPTION, true, "Falcon URL");
-        Option start = new Option(START_OPT, true,
-                "Start time is required for commands, status, kill, suspend, resume and re-run"
-                        + "and it is nominal time while displaying workflow params");
-        Option end = new Option(END_OPT, true,
-                "End time is optional for commands, status, kill, suspend, resume and re-run; "
-                        + "if not specified then current time is considered as end time");
-        Option runid = new Option(RUNID_OPT, true,
-                "Instance runid  is optional and user can specify the runid, defaults to 0");
-        Option clusters = new Option(CLUSTERS_OPT, true,
-                "clusters is optional for commands kill, suspend and resume, "
-                        + "should not be specified for other commands");
-        Option sourceClusters = new Option(SOURCECLUSTER_OPT, true,
-                " source cluster is optional for commands kill, suspend and resume, "
-                        + "should not be specified for other commands (required for only feed)");
-        Option filePath = new Option(FILE_PATH_OPT, true,
-                "Path to job.properties file is required for rerun command, "
-                        + "it should contain name=value pair for properties to override for rerun");
-        Option entityType = new Option(TYPE_OPT, true,
-                "Entity type, can be feed or process xml");
-        Option entityName = new Option(ENTITY_NAME_OPT, true,
-                "Entity name, can be feed or process name");
-        Option colo = new Option(COLO_OPT, true,
-                "Colo on which the cmd has to be executed");
-        Option lifecycle = new Option(LIFECYCLE_OPT, true,
-                "describes life cycle of entity , for feed it can be replication/retention "
-                        + "and for process it can be execution");
-        Option filterBy = new Option(FILTER_BY_OPT, true,
-                "Filter returned instances by the specified fields");
-        Option orderBy = new Option(ORDER_BY_OPT, true,
-                "Order returned instances 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 instances from this offset");
-        Option numResults = new Option(NUM_RESULTS_OPT, true,
-                "Number of results to return per request");
-        Option forceRerun = new Option(FORCE_RERUN_FLAG, false,
-                "Flag to forcefully rerun entire workflow of an instance");
-        Option doAs = new Option(DO_AS_OPT, true, "doAs user");
-        Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout");
-
-        Option instanceTime = new Option(INSTANCE_TIME_OPT, true, "Time for an instance");
-
-        Option allAttempts = new Option(ALL_ATTEMPTS, false, "To get all attempts of corresponding instances");
-
-        instanceOptions.addOption(url);
-        instanceOptions.addOptionGroup(group);
-        instanceOptions.addOption(start);
-        instanceOptions.addOption(end);
-        instanceOptions.addOption(filePath);
-        instanceOptions.addOption(entityType);
-        instanceOptions.addOption(entityName);
-        instanceOptions.addOption(runid);
-        instanceOptions.addOption(clusters);
-        instanceOptions.addOption(sourceClusters);
-        instanceOptions.addOption(colo);
-        instanceOptions.addOption(lifecycle);
-        instanceOptions.addOption(filterBy);
-        instanceOptions.addOption(offset);
-        instanceOptions.addOption(orderBy);
-        instanceOptions.addOption(sortOrder);
-        instanceOptions.addOption(numResults);
-        instanceOptions.addOption(forceRerun);
-        instanceOptions.addOption(doAs);
-        instanceOptions.addOption(debug);
-        instanceOptions.addOption(instanceTime);
-        instanceOptions.addOption(allAttempts);
-
-        return instanceOptions;
-    }
-
-    public void instanceCommand(CommandLine commandLine, FalconClient client) throws FalconCLIException, IOException {
-        Set<String> optionsList = new HashSet<String>();
-        for (Option option : commandLine.getOptions()) {
-            optionsList.add(option.getOpt());
-        }
-
-        String result;
-        String type = commandLine.getOptionValue(TYPE_OPT);
-        String entity = commandLine.getOptionValue(ENTITY_NAME_OPT);
-        String instanceTime = commandLine.getOptionValue(INSTANCE_TIME_OPT);
-        String start = commandLine.getOptionValue(START_OPT);
-        String end = commandLine.getOptionValue(END_OPT);
-        String filePath = commandLine.getOptionValue(FILE_PATH_OPT);
-        String runId = commandLine.getOptionValue(RUNID_OPT);
-        String colo = commandLine.getOptionValue(COLO_OPT);
-        String clusters = commandLine.getOptionValue(CLUSTERS_OPT);
-        String sourceClusters = commandLine.getOptionValue(SOURCECLUSTER_OPT);
-        List<LifeCycle> lifeCycles = getLifeCycle(commandLine.getOptionValue(LIFECYCLE_OPT));
-        String filterBy = commandLine.getOptionValue(FILTER_BY_OPT);
-        String orderBy = commandLine.getOptionValue(ORDER_BY_OPT);
-        String sortOrder = commandLine.getOptionValue(SORT_ORDER_OPT);
-        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
-        Integer offset = parseIntegerInput(commandLine.getOptionValue(OFFSET_OPT), 0, "offset");
-        Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT), null, "numResults");
-
-        colo = getColo(colo);
-        String instanceAction = "instance";
-        validateSortOrder(sortOrder);
-        validateInstanceCommands(optionsList, entity, type, colo);
-
-        if (optionsList.contains(TRIAGE_OPT)) {
-            validateNotEmpty(colo, COLO_OPT);
-            validateNotEmpty(start, START_OPT);
-            validateNotEmpty(type, TYPE_OPT);
-            validateEntityTypeForSummary(type);
-            validateNotEmpty(entity, ENTITY_NAME_OPT);
-            result = client.triage(type, entity, start, colo).toString();
-        } else if (optionsList.contains(DEPENDENCY_OPT)) {
-            validateNotEmpty(instanceTime, INSTANCE_TIME_OPT);
-            InstanceDependencyResult response = client.getInstanceDependencies(type, entity, instanceTime, colo);
-            result = ResponseHelper.getString(response);
-
-        } else if (optionsList.contains(RUNNING_OPT)) {
-            validateOrderBy(orderBy, instanceAction);
-            validateFilterBy(filterBy, instanceAction);
-            result = ResponseHelper.getString(client.getRunningInstances(type,
-                    entity, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser));
-        } else if (optionsList.contains(STATUS_OPT) || optionsList.contains(LIST_OPT)) {
-            boolean allAttempts = false;
-            if (optionsList.contains(ALL_ATTEMPTS)) {
-                allAttempts = true;
-            }
-            validateOrderBy(orderBy, instanceAction);
-            validateFilterBy(filterBy, instanceAction);
-            result = ResponseHelper.getString(client.getStatusOfInstances(type, entity, start, end, colo,
-                    lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser, allAttempts));
-        } else if (optionsList.contains(SUMMARY_OPT)) {
-            validateOrderBy(orderBy, "summary");
-            validateFilterBy(filterBy, "summary");
-            result = ResponseHelper.getString(client.getSummaryOfInstances(type, entity, start, end, colo,
-                    lifeCycles, filterBy, orderBy, sortOrder, doAsUser));
-        } else if (optionsList.contains(KILL_OPT)) {
-            validateNotEmpty(start, START_OPT);
-            validateNotEmpty(end, END_OPT);
-            result = ResponseHelper.getString(client.killInstances(type, entity, start, end, colo, clusters,
-                    sourceClusters, lifeCycles, doAsUser));
-        } else if (optionsList.contains(SUSPEND_OPT)) {
-            validateNotEmpty(start, START_OPT);
-            validateNotEmpty(end, END_OPT);
-            result = ResponseHelper.getString(client.suspendInstances(type, entity, start, end, colo, clusters,
-                    sourceClusters, lifeCycles, doAsUser));
-        } else if (optionsList.contains(RESUME_OPT)) {
-            validateNotEmpty(start, START_OPT);
-            validateNotEmpty(end, END_OPT);
-            result = ResponseHelper.getString(client.resumeInstances(type, entity, start, end, colo, clusters,
-                    sourceClusters, lifeCycles, doAsUser));
-        } else if (optionsList.contains(RERUN_OPT)) {
-            validateNotEmpty(start, START_OPT);
-            validateNotEmpty(end, END_OPT);
-            boolean isForced = false;
-            if (optionsList.contains(FORCE_RERUN_FLAG)) {
-                isForced = true;
-            }
-            result = ResponseHelper.getString(client.rerunInstances(type, entity, start, end, filePath, colo,
-                    clusters, sourceClusters, lifeCycles, isForced, doAsUser));
-        } else if (optionsList.contains(LOG_OPT)) {
-            validateOrderBy(orderBy, instanceAction);
-            validateFilterBy(filterBy, instanceAction);
-            result = ResponseHelper.getString(client.getLogsOfInstances(type, entity, start, end, colo, runId,
-                    lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser), runId);
-        } else if (optionsList.contains(PARARMS_OPT)) {
-            // start time is the nominal time of instance
-            result = ResponseHelper.getString(client.getParamsOfInstance(type, entity,
-                    start, colo, lifeCycles, doAsUser));
-        } else if (optionsList.contains(LISTING_OPT)) {
-            result = ResponseHelper.getString(client.getFeedInstanceListing(type, entity, start, end, colo, doAsUser));
-        } else {
-            throw new FalconCLIException("Invalid command");
-        }
-
-        OUT.get().println(result);
-    }
-
-    private void validateInstanceCommands(Set<String> optionsList,
-                                          String entity, String type,
-                                          String colo) throws FalconCLIException {
-
-        validateNotEmpty(entity, ENTITY_NAME_OPT);
-        validateNotEmpty(type, TYPE_OPT);
-        validateNotEmpty(colo, COLO_OPT);
-
-        if (optionsList.contains(CLUSTERS_OPT)) {
-            if (optionsList.contains(RUNNING_OPT)
-                    || optionsList.contains(LOG_OPT)
-                    || optionsList.contains(STATUS_OPT)
-                    || optionsList.contains(SUMMARY_OPT)) {
-                throw new FalconCLIException("Invalid argument: clusters");
-            }
-        }
-
-        if (optionsList.contains(SOURCECLUSTER_OPT)) {
-            if (optionsList.contains(RUNNING_OPT)
-                    || optionsList.contains(LOG_OPT)
-                    || optionsList.contains(STATUS_OPT)
-                    || optionsList.contains(SUMMARY_OPT) || !type.equals("feed")) {
-                throw new FalconCLIException("Invalid argument: sourceClusters");
-            }
-        }
-
-        if (optionsList.contains(FORCE_RERUN_FLAG)) {
-            if (!optionsList.contains(RERUN_OPT)) {
-                throw new FalconCLIException("Force option can be used only with instance rerun");
-            }
-        }
-    }
-
-    private List<LifeCycle> getLifeCycle(String lifeCycleValue) throws FalconCLIException {
-
-        if (lifeCycleValue != null) {
-            String[] lifeCycleValues = lifeCycleValue.split(",");
-            List<LifeCycle> lifeCycles = new ArrayList<LifeCycle>();
-            try {
-                for (String lifeCycle : lifeCycleValues) {
-                    lifeCycles.add(LifeCycle.valueOf(lifeCycle.toUpperCase().trim()));
-                }
-            } catch (IllegalArgumentException e) {
-                throw new FalconCLIException("Invalid life cycle values: " + lifeCycles, e);
-            }
-            return lifeCycles;
-        }
-        return null;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
deleted file mode 100644
index 6487d41..0000000
--- a/client/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
- * 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.client.FalconCLIException;
-import org.apache.falcon.client.FalconClient;
-import org.apache.falcon.entity.v0.EntityType;
-import org.apache.falcon.metadata.RelationshipType;
-
-import java.io.PrintStream;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Metadata extension to Falcon Command Line Interface - wraps the RESTful API for Metadata.
- */
-public class FalconMetadataCLI extends FalconCLI {
-
-    public static final AtomicReference<PrintStream> OUT = new AtomicReference<PrintStream>(System.out);
-
-    // Discovery Commands
-    public static final String DISCOVERY_OPT = "discovery";
-    public static final String LIST_OPT = "list";
-    public static final String RELATIONS_OPT = "relations";
-    public static final String URL_OPTION = "url";
-    public static final String NAME_OPT = "name";
-
-    // Lineage Commands
-    public static final String LINEAGE_OPT = "lineage";
-    public static final String VERTEX_CMD = "vertex";
-    public static final String VERTICES_CMD = "vertices";
-    public static final String VERTEX_EDGES_CMD = "edges";
-    public static final String PIPELINE_OPT = "pipeline";
-    public static final String EDGE_CMD = "edge";
-    public static final String ID_OPT = "id";
-    public static final String KEY_OPT = "key";
-    public static final String VALUE_OPT = "value";
-    public static final String DIRECTION_OPT = "direction";
-
-    public FalconMetadataCLI() throws Exception {
-        super();
-    }
-
-    public Options createMetadataOptions() {
-        Options metadataOptions = new Options();
-
-        OptionGroup group = new OptionGroup();
-        Option discovery = new Option(DISCOVERY_OPT, false, "Discover falcon metadata relations");
-        Option lineage = new Option(LINEAGE_OPT, false, "Get falcon metadata lineage information");
-        group.addOption(discovery);
-        group.addOption(lineage);
-        Option pipeline = new Option(PIPELINE_OPT, true,
-                "Get lineage graph for the entities in a pipeline");
-        metadataOptions.addOptionGroup(group);
-
-        // Add discovery options
-
-        Option list = new Option(LIST_OPT, false, "List all dimensions");
-        Option relations = new Option(RELATIONS_OPT, false, "List all relations for a dimension");
-        metadataOptions.addOption(list);
-        metadataOptions.addOption(relations);
-
-        Option url = new Option(URL_OPTION, true, "Falcon URL");
-        Option type = new Option(TYPE_OPT, true, "Dimension type");
-        Option name = new Option(NAME_OPT, true, "Dimension name");
-        Option cluster = new Option(CLUSTER_OPT, true, "Cluster name");
-        Option feed = new Option(FEED_OPT, true, "Feed Entity name");
-        Option process = new Option(PROCESS_OPT, true, "Process Entity name");
-        Option numResults = new Option(NUM_RESULTS_OPT, true,
-                "Number of results to return per request");
-
-        // Add lineage options
-        metadataOptions.addOption(pipeline);
-
-        metadataOptions.addOption(url);
-        metadataOptions.addOption(type);
-        metadataOptions.addOption(cluster);
-        metadataOptions.addOption(name);
-        metadataOptions.addOption(feed);
-        metadataOptions.addOption(process);
-        metadataOptions.addOption(numResults);
-
-        Option vertex = new Option(VERTEX_CMD, false, "show the vertices");
-        Option vertices = new Option(VERTICES_CMD, false, "show the vertices");
-        Option vertexEdges = new Option(VERTEX_EDGES_CMD, false, "show the edges for a given vertex");
-        Option edges = new Option(EDGE_CMD, false, "show the edges");
-        Option id = new Option(ID_OPT, true, "vertex or edge id");
-        Option key = new Option(KEY_OPT, true, "key property");
-        Option value = new Option(VALUE_OPT, true, "value property");
-        Option direction = new Option(DIRECTION_OPT, true, "edge direction property");
-        Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout");
-
-        metadataOptions.addOption(vertex);
-        metadataOptions.addOption(vertices);
-        metadataOptions.addOption(vertexEdges);
-        metadataOptions.addOption(edges);
-        metadataOptions.addOption(id);
-        metadataOptions.addOption(key);
-        metadataOptions.addOption(value);
-        metadataOptions.addOption(direction);
-        metadataOptions.addOption(debug);
-
-        Option doAs = new Option(FalconCLI.DO_AS_OPT, true, "doAs user");
-        metadataOptions.addOption(doAs);
-
-        return metadataOptions;
-    }
-
-    public void metadataCommand(CommandLine commandLine, FalconClient client) throws FalconCLIException {
-        Set<String> optionsList = new HashSet<String>();
-        for (Option option : commandLine.getOptions()) {
-            optionsList.add(option.getOpt());
-        }
-
-        String result;
-        String dimensionType = commandLine.getOptionValue(TYPE_OPT);
-        String cluster = commandLine.getOptionValue(CLUSTER_OPT);
-        String feed = commandLine.getOptionValue(FEED_OPT);
-        String process = commandLine.getOptionValue(PROCESS_OPT);
-        String dimensionName = commandLine.getOptionValue(NAME_OPT);
-        String id = commandLine.getOptionValue(ID_OPT);
-        String key = commandLine.getOptionValue(KEY_OPT);
-        String value = commandLine.getOptionValue(VALUE_OPT);
-        String direction = commandLine.getOptionValue(DIRECTION_OPT);
-        String pipeline = commandLine.getOptionValue(PIPELINE_OPT);
-        String doAsUser = commandLine.getOptionValue(FalconCLI.DO_AS_OPT);
-        Integer numResults = parseIntegerInput(commandLine.getOptionValue(NUM_RESULTS_OPT), null, "numResults");
-
-        if (optionsList.contains(LINEAGE_OPT)) {
-            validatePipelineName(pipeline);
-            result = client.getEntityLineageGraph(pipeline, doAsUser).getDotNotation();
-        } else if (optionsList.contains(LIST_OPT)) {
-            validateDimensionType(dimensionType.toUpperCase());
-            if (!(dimensionType.toUpperCase())
-                    .equals(RelationshipType.REPLICATION_METRICS.name())) {
-                result = client.getDimensionList(dimensionType, cluster, doAsUser);
-            } else {
-                String schedEntityType = null;
-                String schedEntityName = null;
-                if (StringUtils.isNotEmpty(feed)) {
-                    schedEntityType = EntityType.getEnum(FEED_OPT).name();
-                    schedEntityName = feed;
-                } else if (StringUtils.isNotEmpty(process)) {
-                    schedEntityType = EntityType.getEnum(PROCESS_OPT).name();
-                    schedEntityName = process;
-                }
-                validateScheduleEntity(schedEntityType, schedEntityName);
-
-                result = client.getReplicationMetricsDimensionList(schedEntityType, schedEntityName,
-                        numResults, doAsUser);
-            }
-        } else if (optionsList.contains(RELATIONS_OPT)) {
-            validateDimensionType(dimensionType.toUpperCase());
-            validateDimensionName(dimensionName, RELATIONS_OPT);
-            result = client.getDimensionRelations(dimensionType, dimensionName, doAsUser);
-        } else if (optionsList.contains(VERTEX_CMD)) {
-            validateId(id);
-            result = client.getVertex(id, doAsUser);
-        } else if (optionsList.contains(VERTICES_CMD)) {
-            validateVerticesCommand(key, value);
-            result = client.getVertices(key, value, doAsUser);
-        } else if (optionsList.contains(VERTEX_EDGES_CMD)) {
-            validateVertexEdgesCommand(id, direction);
-            result = client.getVertexEdges(id, direction, doAsUser);
-        } else if (optionsList.contains(EDGE_CMD)) {
-            validateId(id);
-            result = client.getEdge(id, doAsUser);
-        } else {
-            throw new FalconCLIException("Invalid metadata command");
-        }
-
-        OUT.get().println(result);
-    }
-
-    private void validatePipelineName(String pipeline) throws FalconCLIException {
-        if (StringUtils.isEmpty(pipeline)) {
-            throw new FalconCLIException("Invalid value for pipeline");
-        }
-    }
-
-    private void validateDimensionType(String dimensionType) throws FalconCLIException {
-        if (StringUtils.isEmpty(dimensionType)
-                ||  dimensionType.contains("INSTANCE")) {
-            throw new FalconCLIException("Invalid value provided for queryParam \"type\" " + dimensionType);
-        }
-        try {
-            RelationshipType.valueOf(dimensionType);
-        } catch (IllegalArgumentException iae) {
-            throw new FalconCLIException("Invalid value provided for queryParam \"type\" " + dimensionType);
-        }
-    }
-
-    private void validateDimensionName(String dimensionName, String action) throws FalconCLIException {
-        if (StringUtils.isEmpty(dimensionName)) {
-            throw new FalconCLIException("Dimension ID cannot be empty or null for action " + action);
-        }
-    }
-
-    private void validateScheduleEntity(String schedEntityType, String schedEntityName) throws FalconCLIException {
-        if (StringUtils.isBlank(schedEntityType)) {
-            throw new FalconCLIException("Entity must be schedulable type : -feed/process");
-        }
-
-        if (StringUtils.isBlank(schedEntityName)) {
-            throw new FalconCLIException("Entity name is missing");
-        }
-    }
-
-    private void validateId(String id) throws FalconCLIException {
-        if (id == null || id.length() == 0) {
-            throw new FalconCLIException("Missing argument: id");
-        }
-    }
-
-    private void validateVerticesCommand(String key, String value) throws FalconCLIException {
-        if (key == null || key.length() == 0) {
-            throw new FalconCLIException("Missing argument: key");
-        }
-
-        if (value == null || value.length() == 0) {
-            throw new FalconCLIException("Missing argument: value");
-        }
-    }
-
-    private void validateVertexEdgesCommand(String id, String direction) throws FalconCLIException {
-        if (id == null || id.length() == 0) {
-            throw new FalconCLIException("Missing argument: id");
-        }
-
-        if (direction == null || direction.length() == 0) {
-            throw new FalconCLIException("Missing argument: direction");
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/client/FalconClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/client/FalconClient.java b/client/src/main/java/org/apache/falcon/client/FalconClient.java
index 10243f0..0aaf0ec 100644
--- a/client/src/main/java/org/apache/falcon/client/FalconClient.java
+++ b/client/src/main/java/org/apache/falcon/client/FalconClient.java
@@ -45,9 +45,8 @@ import javax.ws.rs.core.UriBuilder;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.net.util.TrustManagerUtils;
+import org.apache.falcon.FalconCLIConstants;
 import org.apache.falcon.LifeCycle;
-import org.apache.falcon.cli.FalconCLI;
-import org.apache.falcon.cli.FalconMetadataCLI;
 import org.apache.falcon.entity.v0.DateValidator;
 import org.apache.falcon.entity.v0.Entity;
 import org.apache.falcon.entity.v0.EntityType;
@@ -667,7 +666,7 @@ public class FalconClient extends AbstractFalconClient {
     public LineageGraphResult getEntityLineageGraph(String pipelineName, String doAsUser) throws FalconCLIException {
         MetadataOperations operation = MetadataOperations.LINEAGE;
         ClientResponse clientResponse = new ResourceBuilder().path(operation.path).addQueryParam(DO_AS_OPT, doAsUser)
-            .addQueryParam(FalconMetadataCLI.PIPELINE_OPT, pipelineName).call(operation);
+            .addQueryParam(FalconCLIConstants.PIPELINE_OPT, pipelineName).call(operation);
         printClientResponse(clientResponse);
         checkIfSuccessful(clientResponse);
         return clientResponse.getEntity(LineageGraphResult.class);
@@ -861,18 +860,18 @@ public class FalconClient extends AbstractFalconClient {
         WebResource resource = service.path(operation.path)
                 .path(schedEntityName)
                 .path(RelationshipType.REPLICATION_METRICS.getName())
-                .path(FalconMetadataCLI.LIST_OPT);
+                .path(FalconCLIConstants.LIST_OPT);
 
         if (StringUtils.isNotEmpty(schedEntityName)) {
-            resource = resource.queryParam(FalconCLI.TYPE_OPT, schedEntityType);
+            resource = resource.queryParam(FalconCLIConstants.TYPE_OPT, schedEntityType);
         }
 
         if (numResults != null) {
-            resource = resource.queryParam(FalconCLI.NUM_RESULTS_OPT, numResults.toString());
+            resource = resource.queryParam(FalconCLIConstants.NUM_RESULTS_OPT, numResults.toString());
         }
 
         if (StringUtils.isNotEmpty(doAsUser)) {
-            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+            resource = resource.queryParam(FalconCLIConstants.DO_AS_OPT, doAsUser);
         }
 
         ClientResponse clientResponse = resource
@@ -897,14 +896,14 @@ public class FalconClient extends AbstractFalconClient {
         case LIST:
             resource = service.path(operation.path)
                     .path(dimensionType)
-                    .path(FalconMetadataCLI.LIST_OPT);
+                    .path(FalconCLIConstants.LIST_OPT);
             break;
 
         case RELATIONS:
             resource = service.path(operation.path)
                     .path(dimensionType)
                     .path(dimensionName)
-                    .path(FalconMetadataCLI.RELATIONS_OPT);
+                    .path(FalconCLIConstants.RELATIONS_OPT);
             break;
 
         default:
@@ -912,11 +911,11 @@ public class FalconClient extends AbstractFalconClient {
         }
 
         if (!StringUtils.isEmpty(cluster)) {
-            resource = resource.queryParam(FalconMetadataCLI.CLUSTER_OPT, cluster);
+            resource = resource.queryParam(FalconCLIConstants.CLUSTER_OPT, cluster);
         }
 
         if (StringUtils.isNotEmpty(doAsUser)) {
-            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+            resource = resource.queryParam(FalconCLIConstants.DO_AS_OPT, doAsUser);
         }
 
         ClientResponse clientResponse = resource

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/test/java/org/apache/falcon/cli/TestCLIParser.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/falcon/cli/TestCLIParser.java b/client/src/test/java/org/apache/falcon/cli/TestCLIParser.java
deleted file mode 100644
index 6ac3e9f..0000000
--- a/client/src/test/java/org/apache/falcon/cli/TestCLIParser.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * 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.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.testng.Assert;
-import org.testng.annotations.Test;
-
-/**
- * Command parser for CLI.
- */
-public class TestCLIParser {
-
-    @Test
-    public void testEmptyParser() throws Exception {
-        try {
-            CLIParser parser = new CLIParser("falcon", new String[]{});
-            CLIParser.Command c = parser.parse(new String[]{"a"});
-            Assert.fail();
-        } catch (ParseException ex) {
-            // nop
-        }
-    }
-
-    @Test
-    public void testCommandParser() throws Exception {
-        try {
-            CLIParser parser = new CLIParser("oozie", new String[]{});
-            parser.addCommand("a", "<A>", "AAAAA", new Options(), false);
-            CLIParser.Command c = parser.parse(new String[]{"a", "b"});
-            Assert.assertEquals("a", c.getName());
-            Assert.assertEquals("b", c.getCommandLine().getArgs()[0]);
-        } catch (ParseException ex) {
-            Assert.fail();
-        }
-    }
-
-    @Test
-    public void testCommandParserX() throws Exception {
-        Option opt = new Option("o", false, "O");
-        Options opts = new Options();
-        opts.addOption(opt);
-        CLIParser parser = new CLIParser("test", new String[]{});
-        parser.addCommand("c", "-X ",
-                "(everything after '-X' are pass-through parameters)", opts,
-                true);
-        CLIParser.Command c = parser.parse("c -o -X -o c".split(" "));
-        Assert.assertEquals("-X", c.getCommandLine().getArgList().get(0));
-        Assert.assertEquals(3, c.getCommandLine().getArgList().size());
-    }
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/common/src/main/java/org/apache/falcon/cliParser/CLIParser.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/cliParser/CLIParser.java b/common/src/main/java/org/apache/falcon/cliParser/CLIParser.java
new file mode 100644
index 0000000..9bff723
--- /dev/null
+++ b/common/src/main/java/org/apache/falcon/cliParser/CLIParser.java
@@ -0,0 +1,155 @@
+/**
+ * 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.cliParser;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.GnuParser;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.HelpFormatter;
+
+import java.io.PrintWriter;
+import java.text.MessageFormat;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * Cannibalized from Oozie CLIParser into Falcon
+ * Command line parser based on Apache common-cli 1.x that supports subcommands.
+ */
+public class CLIParser {
+    private static final String LEFT_PADDING = "      ";
+
+    private String cliName;
+    private String[] cliHelp;
+    private Map<String, Options> commands = new LinkedHashMap<String, Options>();
+    private Map<String, Boolean> commandWithArgs = new LinkedHashMap<String, Boolean>();
+    private Map<String, String> commandsHelp = new LinkedHashMap<String, String>();
+
+    /**
+     * Create a parser.
+     *
+     * @param aCliName name of the parser, for help purposes.
+     * @param aCliHelp help for the CLI.
+     */
+    public CLIParser(String aCliName, String[] aCliHelp) {
+        this.cliName = aCliName;
+        this.cliHelp = aCliHelp.clone();
+    }
+
+    /**
+     * Add a command to the parser.
+     *
+     * @param command        comand name.
+     * @param argsHelp       command arguments help.
+     * @param commandHelp    command description.
+     * @param commandOptions command options.
+     * @param hasArguments   has args
+     */
+    public void addCommand(String command, String argsHelp, String commandHelp, Options commandOptions,
+                           boolean hasArguments) {
+        String helpMsg = argsHelp + ((hasArguments) ? "<ARGS> " : "") + ": " + commandHelp;
+        commandsHelp.put(command, helpMsg);
+        commands.put(command, commandOptions);
+        commandWithArgs.put(command, hasArguments);
+    }
+
+    /**
+     * Bean that represents a parsed command.
+     */
+    public static final class Command {
+        private String name;
+        private CommandLine commandLine;
+
+        private Command(String name, CommandLine commandLine) {
+            this.name = name;
+            this.commandLine = commandLine;
+        }
+
+        /**
+         * Return the command name.
+         *
+         * @return the command name.
+         */
+        public String getName() {
+            return name;
+        }
+
+        /**
+         * Return the command line.
+         *
+         * @return the command line.
+         */
+        public CommandLine getCommandLine() {
+            return commandLine;
+        }
+    }
+
+    /**
+     * Parse a array of arguments into a command.
+     *
+     * @param args array of arguments.
+     * @return the parsed Command.
+     * @throws ParseException thrown if the arguments could not be parsed.
+     */
+    public Command parse(String[] args) throws ParseException {
+        if (args.length == 0) {
+            throw new ParseException("missing sub-command");
+        } else {
+            if (commands.containsKey(args[0])) {
+                GnuParser parser = new GnuParser();
+                String[] minusCommand = new String[args.length - 1];
+                System.arraycopy(args, 1, minusCommand, 0, minusCommand.length);
+                return new Command(args[0], parser.parse(commands.get(args[0]), minusCommand,
+                        commandWithArgs.get(args[0])));
+            } else {
+                throw new ParseException(MessageFormat.format("invalid sub-command [{0}]", args[0]));
+            }
+        }
+    }
+
+    public String shortHelp() {
+        return "use 'help' sub-command for help details";
+    }
+
+    /**
+     * Print the help for the parser to standard output.
+     */
+    public void showHelp() {
+        PrintWriter pw = new PrintWriter(System.out);
+        pw.println("usage: ");
+        for (String s : cliHelp) {
+            pw.println(LEFT_PADDING + s);
+        }
+        pw.println();
+        HelpFormatter formatter = new HelpFormatter();
+        for (Map.Entry<String, Options> entry : commands.entrySet()) {
+            String s = LEFT_PADDING + cliName + " " + entry.getKey() + " ";
+            if (entry.getValue().getOptions().size() > 0) {
+                pw.println(s + "<OPTIONS> " + commandsHelp.get(entry.getKey()));
+                formatter.printOptions(pw, 100, entry.getValue(), s.length(), 3);
+            } else {
+                pw.println(s + commandsHelp.get(entry.getKey()));
+            }
+            pw.println();
+        }
+        pw.flush();
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/common/src/main/java/org/apache/falcon/tools/FalconStateStoreDBCLI.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/falcon/tools/FalconStateStoreDBCLI.java b/common/src/main/java/org/apache/falcon/tools/FalconStateStoreDBCLI.java
index df8194c..d56087a 100644
--- a/common/src/main/java/org/apache/falcon/tools/FalconStateStoreDBCLI.java
+++ b/common/src/main/java/org/apache/falcon/tools/FalconStateStoreDBCLI.java
@@ -21,7 +21,7 @@ import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
-import org.apache.falcon.cli.CLIParser;
+import org.apache.falcon.cliParser.CLIParser;
 import org.apache.falcon.service.FalconJPAService;
 import org.apache.falcon.util.BuildProperties;
 import org.apache.falcon.util.StateStoreProperties;

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/common/src/test/java/cli/TestCLIParser.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/cli/TestCLIParser.java b/common/src/test/java/cli/TestCLIParser.java
new file mode 100644
index 0000000..164f531
--- /dev/null
+++ b/common/src/test/java/cli/TestCLIParser.java
@@ -0,0 +1,70 @@
+/**
+ * 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 cli;
+
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.falcon.cliParser.CLIParser;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ * Command parser for CLI.
+ */
+public class TestCLIParser {
+
+    @Test
+    public void testEmptyParser() throws Exception {
+        try {
+            CLIParser parser = new CLIParser("falcon", new String[]{});
+            CLIParser.Command c = parser.parse(new String[]{"a"});
+            Assert.fail();
+        } catch (ParseException ex) {
+            // nop
+        }
+    }
+
+    @Test
+    public void testCommandParser() throws Exception {
+        try {
+            CLIParser parser = new CLIParser("oozie", new String[]{});
+            parser.addCommand("a", "<A>", "AAAAA", new Options(), false);
+            CLIParser.Command c = parser.parse(new String[]{"a", "b"});
+            Assert.assertEquals("a", c.getName());
+            Assert.assertEquals("b", c.getCommandLine().getArgs()[0]);
+        } catch (ParseException ex) {
+            Assert.fail();
+        }
+    }
+
+    @Test
+    public void testCommandParserX() throws Exception {
+        Option opt = new Option("o", false, "O");
+        Options opts = new Options();
+        opts.addOption(opt);
+        CLIParser parser = new CLIParser("test", new String[]{});
+        parser.addCommand("c", "-X ",
+                "(everything after '-X' are pass-through parameters)", opts,
+                true);
+        CLIParser.Command c = parser.parse("c -o -X -o c".split(" "));
+        Assert.assertEquals("-X", c.getCommandLine().getArgList().get(0));
+        Assert.assertEquals(3, c.getCommandLine().getArgList().size());
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/webapp/pom.xml
----------------------------------------------------------------------
diff --git a/webapp/pom.xml b/webapp/pom.xml
index 06aa897..dad0581 100644
--- a/webapp/pom.xml
+++ b/webapp/pom.xml
@@ -274,6 +274,12 @@
             <type>war</type>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.falcon</groupId>
+            <artifactId>falcon-cli</artifactId>
+            <version>0.10-SNAPSHOT</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
index 4805597..5ce8893 100644
--- a/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
+++ b/webapp/src/test/java/org/apache/falcon/cli/FalconCLIIT.java
@@ -18,6 +18,7 @@
 
 package org.apache.falcon.cli;
 
+import org.apache.falcon.FalconCLIConstants;
 import org.apache.falcon.entity.v0.SchemaHelper;
 import org.apache.falcon.metadata.RelationshipType;
 import org.apache.falcon.resource.TestContext;
@@ -713,22 +714,21 @@ public class FalconCLIIT {
         String feedName = overlay.get("outputFeedName");
         String clusterName = overlay.get("cluster");
 
-        Assert.assertEquals(executeWithURL(FalconCLI.ENTITY_CMD + " -" + FalconCLI.SCHEDULE_OPT + " -"
-                        + FalconCLI.TYPE_OPT + " process  -" + FalconCLI.ENTITY_NAME_OPT + " " + processName),
-                0);
+        Assert.assertEquals(executeWithURL(FalconCLIConstants.ENTITY_CMD + " -" + FalconCLIConstants.SCHEDULE_OPT + " -"
+                        + FalconCLIConstants.TYPE_OPT + " process  -"
+                + FalconCLIConstants.ENTITY_NAME_OPT + " " + processName), 0);
 
-        Assert.assertEquals(executeWithURL(FalconCLI.ENTITY_CMD + " -" + FalconCLI.SCHEDULE_OPT + " -"
-                + FalconCLI.TYPE_OPT + " feed -" + FalconCLI.ENTITY_NAME_OPT + " " + feedName), 0);
+        Assert.assertEquals(executeWithURL(FalconCLIConstants.ENTITY_CMD + " -" + FalconCLIConstants.SCHEDULE_OPT + " -"
+                + FalconCLIConstants.TYPE_OPT + " feed -" + FalconCLIConstants.ENTITY_NAME_OPT + " " + feedName), 0);
 
         OozieTestUtils.waitForProcessWFtoStart(context);
 
-        String metadataListCommand = FalconCLI.METADATA_CMD + " -" + FalconMetadataCLI.LIST_OPT + " -"
-                + FalconMetadataCLI.TYPE_OPT + " ";
-        String metadataListCommandWithDoAs = FalconCLI.METADATA_CMD + " -doAs " + FalconTestUtil.TEST_USER_2 + " -"
-                + FalconMetadataCLI.LIST_OPT + " -"
-                + FalconMetadataCLI.TYPE_OPT + " ";
+        String metadataListCommand = FalconCLIConstants.METADATA_CMD + " -" + FalconCLIConstants.LIST_OPT + " -"
+                + FalconCLIConstants.TYPE_OPT + " ";
+        String metadataListCommandWithDoAs = FalconCLIConstants.METADATA_CMD + " -doAs " + FalconTestUtil.TEST_USER_2
+                + " -" + FalconCLIConstants.LIST_OPT + " -" + FalconCLIConstants.TYPE_OPT + " ";
 
-        String clusterString = " -" + FalconMetadataCLI.CLUSTER_OPT + " " + clusterName;
+        String clusterString = " -" + FalconCLIConstants.CLUSTER_OPT + " " + clusterName;
 
         Assert.assertEquals(executeWithURL(metadataListCommand + RelationshipType.CLUSTER_ENTITY.name()), 0);
         Assert.assertEquals(executeWithURL(metadataListCommand + RelationshipType.PROCESS_ENTITY.name()), 0);
@@ -757,36 +757,36 @@ public class FalconCLIIT {
         String feedName = overlay.get("outputFeedName");
         String clusterName = overlay.get("cluster");
 
-        Assert.assertEquals(executeWithURL(FalconCLI.ENTITY_CMD + " -" + FalconCLI.SCHEDULE_OPT + " -"
-                        + FalconCLI.TYPE_OPT + " process  -" + FalconCLI.ENTITY_NAME_OPT + " " + processName),
-                0);
+        Assert.assertEquals(executeWithURL(FalconCLIConstants.ENTITY_CMD + " -" + FalconCLIConstants.SCHEDULE_OPT + " -"
+                        + FalconCLIConstants.TYPE_OPT + " process  -"
+                + FalconCLIConstants.ENTITY_NAME_OPT + " " + processName), 0);
 
-        Assert.assertEquals(executeWithURL(FalconCLI.ENTITY_CMD + " -" + FalconCLI.SCHEDULE_OPT + " -"
-                + FalconCLI.TYPE_OPT + " feed -" + FalconCLI.ENTITY_NAME_OPT + " " + feedName), 0);
+        Assert.assertEquals(executeWithURL(FalconCLIConstants.ENTITY_CMD + " -" + FalconCLIConstants.SCHEDULE_OPT + " -"
+                + FalconCLIConstants.TYPE_OPT + " feed -" + FalconCLIConstants.ENTITY_NAME_OPT + " " + feedName), 0);
 
         OozieTestUtils.waitForProcessWFtoStart(context);
 
-        String metadataRelationsCommand = FalconCLI.METADATA_CMD + " -" + FalconMetadataCLI.RELATIONS_OPT + " -"
-                + FalconMetadataCLI.TYPE_OPT + " ";
+        String metadataRelationsCommand = FalconCLIConstants.METADATA_CMD + " -"
+                + FalconCLIConstants.RELATIONS_OPT + " -" + FalconCLIConstants.TYPE_OPT + " ";
 
-        String metadataRelationsCommandWithDoAs = FalconCLI.METADATA_CMD + " -doAs " + FalconTestUtil.TEST_USER_2
-                + " -" + FalconMetadataCLI.RELATIONS_OPT + " -"
-                + FalconMetadataCLI.TYPE_OPT + " ";
+        String metadataRelationsCommandWithDoAs = FalconCLIConstants.METADATA_CMD
+                + " -doAs " + FalconTestUtil.TEST_USER_2 + " -" + FalconCLIConstants.RELATIONS_OPT + " -"
+                + FalconCLIConstants.TYPE_OPT + " ";
 
         Assert.assertEquals(executeWithURL(metadataRelationsCommand + RelationshipType.CLUSTER_ENTITY.name()
-                + " -" + FalconMetadataCLI.NAME_OPT + " " + clusterName), 0);
+                + " -" + FalconCLIConstants.NAME_OPT + " " + clusterName), 0);
         Assert.assertEquals(executeWithURL(metadataRelationsCommand + RelationshipType.PROCESS_ENTITY.name()
-                + " -" + FalconMetadataCLI.NAME_OPT + " " + processName), 0);
+                + " -" + FalconCLIConstants.NAME_OPT + " " + processName), 0);
 
         // with doAs
         Assert.assertEquals(executeWithURL(metadataRelationsCommandWithDoAs + RelationshipType.PROCESS_ENTITY.name()
-                + " -" + FalconMetadataCLI.NAME_OPT + " " + processName), 0);
+                + " -" + FalconCLIConstants.NAME_OPT + " " + processName), 0);
 
         Assert.assertEquals(executeWithURL(metadataRelationsCommand + "feed -"
-                + FalconMetadataCLI.NAME_OPT + " " + clusterName), -1);
+                + FalconCLIConstants.NAME_OPT + " " + clusterName), -1);
 
         Assert.assertEquals(executeWithURL(metadataRelationsCommand + "invalid -"
-                + FalconMetadataCLI.NAME_OPT + " " + clusterName), -1);
+                + FalconCLIConstants.NAME_OPT + " " + clusterName), -1);
         Assert.assertEquals(executeWithURL(metadataRelationsCommand + RelationshipType.CLUSTER_ENTITY.name()), -1);
     }
 

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/webapp/src/test/java/org/apache/falcon/resource/TestContext.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/falcon/resource/TestContext.java b/webapp/src/test/java/org/apache/falcon/resource/TestContext.java
index e3fe8bb..f84559f 100644
--- a/webapp/src/test/java/org/apache/falcon/resource/TestContext.java
+++ b/webapp/src/test/java/org/apache/falcon/resource/TestContext.java
@@ -27,6 +27,7 @@ import com.sun.jersey.client.urlconnection.HTTPSProperties;
 import org.apache.commons.lang.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.net.util.TrustManagerUtils;
+import org.apache.falcon.FalconCLIConstants;
 import org.apache.falcon.FalconException;
 import org.apache.falcon.FalconRuntimException;
 import org.apache.falcon.catalog.HiveCatalogService;
@@ -304,7 +305,7 @@ public class TestContext extends AbstractTestContext {
         }
 
         if (StringUtils.isNotEmpty(doAsUser)) {
-            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+            resource = resource.queryParam(FalconCLIConstants.DO_AS_OPT, doAsUser);
         }
 
         if (StringUtils.isNotEmpty(properties)) {
@@ -408,7 +409,7 @@ public class TestContext extends AbstractTestContext {
         WebResource resource = this.service.path("api/entities/submit/" + entityType.name().toLowerCase());
 
         if (StringUtils.isNotEmpty(doAsUser)) {
-            resource = resource.queryParam(FalconCLI.DO_AS_OPT, doAsUser);
+            resource = resource.queryParam(FalconCLIConstants.DO_AS_OPT, doAsUser);
         }
 
         return resource.header("Cookie", getAuthenticationToken())


[2/2] falcon git commit: FALCON-1895 Refactoring of FalconCLI and FalconClient

Posted by pe...@apache.org.
FALCON-1895 Refactoring of FalconCLI and FalconClient

Author: Praveen Adlakha <ad...@gmail.com>

Reviewers: Peeyush Bishnoi<pe...@apache.org>, Balu<bv...@hortonworks.com>, Sowmya<sr...@hortonworks.com>

Closes #94 from PraveenAdlakha/1895 and squashes the following commits:

00a65a2 [Praveen Adlakha] merge conflicts resolved
d069466 [Praveen Adlakha] sync from upstream
4e79efc [Praveen Adlakha] extra space removed
d8bc106 [Praveen Adlakha] FALCON-1895 Refactoring of FalconCLI and FalconClient


Project: http://git-wip-us.apache.org/repos/asf/falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/falcon/commit/6655e90a
Tree: http://git-wip-us.apache.org/repos/asf/falcon/tree/6655e90a
Diff: http://git-wip-us.apache.org/repos/asf/falcon/diff/6655e90a

Branch: refs/heads/master
Commit: 6655e90a7b3990cbe8dffd2e20d3657c249b123e
Parents: 3e22a77
Author: Praveen Adlakha <ad...@gmail.com>
Authored: Wed Apr 13 21:09:37 2016 +0530
Committer: peeyush b <pb...@hortonworks.com>
Committed: Wed Apr 13 21:09:37 2016 +0530

----------------------------------------------------------------------
 cli/pom.xml                                     |  15 +-
 .../org/apache/falcon/cli/FalconAdminCLI.java   | 111 ++++++
 .../java/org/apache/falcon/cli/FalconCLI.java   | 283 +++++++++++++++
 .../org/apache/falcon/cli/FalconEntityCLI.java  | 362 +++++++++++++++++++
 .../apache/falcon/cli/FalconInstanceCLI.java    | 340 +++++++++++++++++
 .../apache/falcon/cli/FalconMetadataCLI.java    | 256 +++++++++++++
 .../org/apache/falcon/FalconCLIConstants.java   |  76 ++++
 .../java/org/apache/falcon/cli/CLIParser.java   | 155 --------
 .../org/apache/falcon/cli/FalconAdminCLI.java   | 109 ------
 .../java/org/apache/falcon/cli/FalconCLI.java   | 318 ----------------
 .../org/apache/falcon/cli/FalconEntityCLI.java  | 360 ------------------
 .../apache/falcon/cli/FalconInstanceCLI.java    | 336 -----------------
 .../apache/falcon/cli/FalconMetadataCLI.java    | 256 -------------
 .../org/apache/falcon/client/FalconClient.java  |  21 +-
 .../org/apache/falcon/cli/TestCLIParser.java    |  69 ----
 .../org/apache/falcon/cliParser/CLIParser.java  | 155 ++++++++
 .../falcon/tools/FalconStateStoreDBCLI.java     |   2 +-
 common/src/test/java/cli/TestCLIParser.java     |  70 ++++
 webapp/pom.xml                                  |   6 +
 .../java/org/apache/falcon/cli/FalconCLIIT.java |  52 +--
 .../org/apache/falcon/resource/TestContext.java |   5 +-
 21 files changed, 1710 insertions(+), 1647 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/pom.xml
----------------------------------------------------------------------
diff --git a/cli/pom.xml b/cli/pom.xml
index 408c6ee..ff4a16b 100644
--- a/cli/pom.xml
+++ b/cli/pom.xml
@@ -53,10 +53,7 @@
     </profiles>
 
     <dependencies>
-        <dependency>
-            <groupId>org.apache.falcon</groupId>
-            <artifactId>falcon-client</artifactId>
-        </dependency>
+
 
         <dependency>
             <groupId>commons-net</groupId>
@@ -142,6 +139,16 @@
             <artifactId>spring-beans</artifactId>
             <version>4.0.3.RELEASE</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.falcon</groupId>
+            <artifactId>falcon-client</artifactId>
+            <version>0.10-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.falcon</groupId>
+            <artifactId>falcon-common</artifactId>
+            <version>0.10-SNAPSHOT</version>
+        </dependency>
 
     </dependencies>
 

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
----------------------------------------------------------------------
diff --git a/cli/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java b/cli/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
new file mode 100644
index 0000000..56cc5b9
--- /dev/null
+++ b/cli/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
@@ -0,0 +1,111 @@
+/**
+ * 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.falcon.FalconCLIConstants;
+import org.apache.falcon.client.FalconCLIException;
+import org.apache.falcon.client.FalconClient;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Admin extension to Falcon Command Line Interface - wraps the RESTful API for admin commands.
+ */
+public class FalconAdminCLI extends FalconCLI {
+
+    private static final String STACK_OPTION = "stack";
+
+    public FalconAdminCLI() throws Exception {
+        super();
+    }
+
+    public Options createAdminOptions() {
+        Options adminOptions = new Options();
+        Option url = new Option(FalconCLIConstants.URL_OPTION, true, "Falcon URL");
+        adminOptions.addOption(url);
+
+        OptionGroup group = new OptionGroup();
+        Option status = new Option(FalconCLIConstants.STATUS_OPT, false,
+                "show the current system status");
+        Option version = new Option(FalconCLIConstants.VERSION_OPT, false,
+                "show Falcon server build version");
+        Option stack = new Option(STACK_OPTION, false,
+                "show the thread stack dump");
+        Option doAs = new Option(FalconCLIConstants.DO_AS_OPT, true,
+                "doAs user");
+        Option help = new Option("help", false, "show Falcon help");
+        Option debug = new Option(FalconCLIConstants.DEBUG_OPTION, false,
+                "Use debug mode to see debugging statements on stdout");
+        group.addOption(status);
+        group.addOption(version);
+        group.addOption(stack);
+        group.addOption(help);
+
+        adminOptions.addOptionGroup(group);
+        adminOptions.addOption(doAs);
+        adminOptions.addOption(debug);
+        return adminOptions;
+    }
+
+    public int adminCommand(CommandLine commandLine, FalconClient client,
+                             String falconUrl) throws FalconCLIException, IOException {
+        String result;
+        Set<String> optionsList = new HashSet<String>();
+        for (Option option : commandLine.getOptions()) {
+            optionsList.add(option.getOpt());
+        }
+
+        String doAsUser = commandLine.getOptionValue(FalconCLIConstants.DO_AS_OPT);
+
+        if (optionsList.contains(STACK_OPTION)) {
+            result = client.getThreadDump(doAsUser);
+            OUT.get().println(result);
+        }
+
+        int exitValue = 0;
+        if (optionsList.contains(FalconCLIConstants.STATUS_OPT)) {
+            try {
+                int status = client.getStatus(doAsUser);
+                if (status != 200) {
+                    ERR.get().println("Falcon server is not fully operational (on " + falconUrl + "). "
+                            + "Please check log files.");
+                    exitValue = status;
+                } else {
+                    OUT.get().println("Falcon server is running (on " + falconUrl + ")");
+                }
+            } catch (Exception e) {
+                ERR.get().println("Falcon server doesn't seem to be running on " + falconUrl);
+                exitValue = -1;
+            }
+        } else if (optionsList.contains(FalconCLIConstants.VERSION_OPT)) {
+            result = client.getVersion(doAsUser);
+            OUT.get().println("Falcon server build version: " + result);
+        } else if (optionsList.contains(FalconCLIConstants.HELP_CMD)) {
+            OUT.get().println("Falcon Help");
+        }
+        return exitValue;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/src/main/java/org/apache/falcon/cli/FalconCLI.java
----------------------------------------------------------------------
diff --git a/cli/src/main/java/org/apache/falcon/cli/FalconCLI.java b/cli/src/main/java/org/apache/falcon/cli/FalconCLI.java
new file mode 100644
index 0000000..a414c94
--- /dev/null
+++ b/cli/src/main/java/org/apache/falcon/cli/FalconCLI.java
@@ -0,0 +1,283 @@
+/**
+ * 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 com.sun.jersey.api.client.ClientHandlerException;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.falcon.FalconCLIConstants;
+import org.apache.falcon.cliParser.CLIParser;
+import org.apache.falcon.client.FalconCLIException;
+import org.apache.falcon.client.FalconClient;
+import org.apache.falcon.entity.v0.EntityType;
+import org.apache.falcon.resource.EntityList;
+import org.apache.falcon.resource.InstancesResult;
+import org.apache.falcon.resource.InstancesSummaryResult;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Falcon Command Line Interface - wraps the RESTful API.
+ */
+public class FalconCLI {
+
+    public static final AtomicReference<PrintStream> ERR = new AtomicReference<PrintStream>(System.err);
+    public static final AtomicReference<PrintStream> OUT = new AtomicReference<PrintStream>(System.out);
+
+    private static final String FALCON_URL = "FALCON_URL";
+    private final Properties clientProperties;
+
+    public FalconCLI() throws Exception {
+        clientProperties = getClientProperties();
+    }
+
+    /**
+     * Entry point for the Falcon CLI when invoked from the command line. Upon
+     * completion this method exits the JVM with '0' (success) or '-1'
+     * (failure).
+     *
+     * @param args options and arguments for the Falcon CLI.
+     */
+    public static void main(final String[] args) throws Exception {
+        System.exit(new FalconCLI().run(args));
+    }
+
+    // TODO help and headers
+    private static final String[] FALCON_HELP = { "the env variable '" + FALCON_URL
+            + "' is used as default value for the '-"
+            + FalconCLIConstants.URL_OPTION + "' option",
+                                                  "custom headers for Falcon web services can be specified using '-D"
+                                                          + FalconClient.WS_HEADER_PREFIX + "NAME=VALUE'", };
+    /**
+     * Run a CLI programmatically.
+     * <p/>
+     * It does not exit the JVM.
+     * <p/>
+     * A CLI instance can be used only once.
+     *
+     * @param args options and arguments for the Oozie CLI.
+     * @return '0' (success), '-1' (failure).
+     */
+    public synchronized int run(final String[] args) throws Exception {
+
+        CLIParser parser = new CLIParser("falcon", FALCON_HELP);
+
+        FalconAdminCLI adminCLI = new FalconAdminCLI();
+        FalconEntityCLI entityCLI = new FalconEntityCLI();
+        FalconInstanceCLI instanceCLI = new FalconInstanceCLI();
+        FalconMetadataCLI metadataCLI = new FalconMetadataCLI();
+
+        parser.addCommand(FalconCLIConstants.ADMIN_CMD, "", "admin operations", adminCLI.createAdminOptions(), true);
+        parser.addCommand(FalconCLIConstants.HELP_CMD, "", "display usage", new Options(), false);
+        parser.addCommand(FalconCLIConstants.ENTITY_CMD, "",
+                "Entity operations like submit, suspend, resume, delete, status, definition, submitAndSchedule",
+                entityCLI.createEntityOptions(), false);
+        parser.addCommand(FalconCLIConstants.INSTANCE_CMD, "",
+                "Process instances operations like running, status, kill, suspend, resume, rerun, logs",
+                instanceCLI.createInstanceOptions(), false);
+        parser.addCommand(FalconCLIConstants.METADATA_CMD, "", "Metadata operations like list, relations",
+                metadataCLI.createMetadataOptions(), true);
+        parser.addCommand(FalconCLIConstants.VERSION_OPT, "", "show client version", new Options(), false);
+
+        try {
+            CLIParser.Command command = parser.parse(args);
+            int exitValue = 0;
+            if (command.getName().equals(FalconCLIConstants.HELP_CMD)) {
+                parser.showHelp();
+            } else {
+                CommandLine commandLine = command.getCommandLine();
+                String falconUrl = getFalconEndpoint(commandLine);
+                FalconClient client = new FalconClient(falconUrl, clientProperties);
+
+                setDebugMode(client, commandLine.hasOption(FalconCLIConstants.DEBUG_OPTION));
+                if (command.getName().equals(FalconCLIConstants.ADMIN_CMD)) {
+                    exitValue = adminCLI.adminCommand(commandLine, client, falconUrl);
+                } else if (command.getName().equals(FalconCLIConstants.ENTITY_CMD)) {
+                    entityCLI.entityCommand(commandLine, client);
+                } else if (command.getName().equals(FalconCLIConstants.INSTANCE_CMD)) {
+                    instanceCLI.instanceCommand(commandLine, client);
+                } else if (command.getName().equals(FalconCLIConstants.METADATA_CMD)) {
+                    metadataCLI.metadataCommand(commandLine, client);
+                }
+            }
+            return exitValue;
+        } catch (ParseException ex) {
+            ERR.get().println("Invalid sub-command: " + ex.getMessage());
+            ERR.get().println();
+            ERR.get().println(parser.shortHelp());
+            ERR.get().println("Stacktrace:");
+            ex.printStackTrace();
+            return -1;
+        } catch (ClientHandlerException ex) {
+            ERR.get().print("Unable to connect to Falcon server, "
+                    + "please check if the URL is correct and Falcon server is up and running\n");
+            ERR.get().println("Stacktrace:");
+            ex.printStackTrace();
+            return -1;
+        } catch (FalconCLIException e) {
+            ERR.get().println("ERROR: " + e.getMessage());
+            return -1;
+        } catch (Exception ex) {
+            ERR.get().println("Stacktrace:");
+            ex.printStackTrace();
+            return -1;
+        }
+    }
+
+    protected Integer parseIntegerInput(String optionValue, Integer defaultVal, String optionName)
+        throws FalconCLIException {
+        Integer integer = defaultVal;
+        if (optionValue != null) {
+            try {
+                return Integer.parseInt(optionValue);
+            } catch (NumberFormatException e) {
+                throw new FalconCLIException("Input value provided for queryParam \""+ optionName
+                        +"\" is not a valid Integer");
+            }
+        }
+        return integer;
+    }
+
+    protected void validateEntityTypeForSummary(String type) throws FalconCLIException {
+        EntityType entityType = EntityType.getEnum(type);
+        if (!entityType.isSchedulable()) {
+            throw new FalconCLIException("Invalid entity type " + entityType
+                    + " for EntitySummary API. Valid options are feed or process");
+        }
+    }
+
+    protected void validateNotEmpty(String paramVal, String paramName) throws FalconCLIException {
+        if (StringUtils.isBlank(paramVal)) {
+            throw new FalconCLIException("Missing argument : " + paramName);
+        }
+    }
+
+    protected void validateSortOrder(String sortOrder) throws FalconCLIException {
+        if (!StringUtils.isBlank(sortOrder)) {
+            if (!sortOrder.equalsIgnoreCase("asc") && !sortOrder.equalsIgnoreCase("desc")) {
+                throw new FalconCLIException("Value for param sortOrder should be \"asc\" or \"desc\". It is  : "
+                        + sortOrder);
+            }
+        }
+    }
+
+    protected String getColo(String colo) throws FalconCLIException, IOException {
+        if (colo == null) {
+            Properties prop = getClientProperties();
+            colo = prop.getProperty(FalconCLIConstants.CURRENT_COLO, "*");
+        }
+        return colo;
+    }
+
+    protected void validateFilterBy(String filterBy, String filterType) throws FalconCLIException {
+        if (StringUtils.isEmpty(filterBy)) {
+            return;
+        }
+        String[] filterSplits = filterBy.split(",");
+        for (String s : filterSplits) {
+            String[] tempKeyVal = s.split(":", 2);
+            try {
+                if (filterType.equals("entity")) {
+                    EntityList.EntityFilterByFields.valueOf(tempKeyVal[0].toUpperCase());
+                } else if (filterType.equals("instance")) {
+                    InstancesResult.InstanceFilterFields.valueOf(tempKeyVal[0].toUpperCase());
+                }else if (filterType.equals("summary")) {
+                    InstancesSummaryResult.InstanceSummaryFilterFields.valueOf(tempKeyVal[0].toUpperCase());
+                } else {
+                    throw new IllegalArgumentException("Invalid API call: filterType is not valid");
+                }
+            } catch (IllegalArgumentException ie) {
+                throw new FalconCLIException("Invalid filterBy argument : " + tempKeyVal[0] + " in : " + s);
+            }
+        }
+    }
+
+    protected void validateOrderBy(String orderBy, String action) throws FalconCLIException {
+        if (StringUtils.isBlank(orderBy)) {
+            return;
+        }
+        if (action.equals("instance")) {
+            if (Arrays.asList(new String[]{"status", "cluster", "starttime", "endtime"})
+                .contains(orderBy.toLowerCase())) {
+                return;
+            }
+        } else if (action.equals("entity")) {
+            if (Arrays.asList(new String[] {"type", "name"}).contains(orderBy.toLowerCase())) {
+                return;
+            }
+        } else if (action.equals("summary")) {
+            if (Arrays.asList(new String[]{"cluster"})
+                    .contains(orderBy.toLowerCase())) {
+                return;
+            }
+        }
+        throw new FalconCLIException("Invalid orderBy argument : " + orderBy);
+    }
+
+    protected String getFalconEndpoint(CommandLine commandLine) throws FalconCLIException, IOException {
+        String url = commandLine.getOptionValue(FalconCLIConstants.URL_OPTION);
+        if (url == null) {
+            url = System.getenv(FALCON_URL);
+        }
+        if (url == null) {
+            if (clientProperties.containsKey("falcon.url")) {
+                url = clientProperties.getProperty("falcon.url");
+            }
+        }
+        if (url == null) {
+            throw new FalconCLIException("Failed to get falcon url from cmdline, or environment or client properties");
+        }
+
+        return url;
+    }
+
+    private void setDebugMode(FalconClient client, boolean debugOpt) {
+        String debug = System.getenv(FalconCLIConstants.ENV_FALCON_DEBUG);
+        if (debugOpt) {  // CLI argument "-debug" used
+            client.setDebugMode(true);
+        } else if (StringUtils.isNotBlank(debug)) {
+            System.out.println(FalconCLIConstants.ENV_FALCON_DEBUG + ": " + debug);
+            if (debug.trim().toLowerCase().equals("true")) {
+                client.setDebugMode(true);
+            }
+        }
+    }
+
+    private Properties getClientProperties() throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = FalconCLI.class.getResourceAsStream(FalconCLIConstants.CLIENT_PROPERTIES);
+            Properties prop = new Properties();
+            if (inputStream != null) {
+                prop.load(inputStream);
+            }
+            return prop;
+        } finally {
+            IOUtils.closeQuietly(inputStream);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
----------------------------------------------------------------------
diff --git a/cli/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java b/cli/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
new file mode 100644
index 0000000..fa71d67
--- /dev/null
+++ b/cli/src/main/java/org/apache/falcon/cli/FalconEntityCLI.java
@@ -0,0 +1,362 @@
+/**
+ * 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.FalconCLIConstants;
+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";
+    private static final String SHOWSCHEDULER_OPT = "showScheduler";
+
+    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(FalconCLIConstants.SCHEDULE_OPT, false,
+                "Schedules a submited entity in Falcon");
+        Option suspend = new Option(FalconCLIConstants.SUSPEND_OPT, false,
+                "Suspends a running entity in Falcon");
+        Option resume = new Option(FalconCLIConstants.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(FalconCLIConstants.STATUS_OPT, false,
+                "Gets the status of entity");
+        Option definition = new Option(DEFINITION_OPT, false,
+                "Gets the Definition of entity");
+        Option dependency = new Option(FalconCLIConstants.DEPENDENCY_OPT, false,
+                "Gets the dependencies of entity");
+        Option list = new Option(FalconCLIConstants.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(FalconCLIConstants.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(FalconCLIConstants.URL_OPTION, true, "Falcon URL");
+        Option entityType = new Option(FalconCLIConstants.TYPE_OPT, true,
+                "Entity type, can be cluster, feed or process xml");
+        Option filePath = new Option(FalconCLIConstants.FILE_PATH_OPT, true,
+                "Path to entity xml file");
+        Option entityName = new Option(FalconCLIConstants.ENTITY_NAME_OPT, true,
+                "Entity type, can be cluster, feed or process xml");
+        Option start = new Option(FalconCLIConstants.START_OPT, true, "Start time is optional for summary");
+        Option end = new Option(FalconCLIConstants.END_OPT, true, "End time is optional for summary");
+        Option colo = new Option(FalconCLIConstants.COLO_OPT, true, "Colo name");
+        Option cluster = new Option(FalconCLIConstants.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(FalconCLIConstants.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(FalconCLIConstants.ORDER_BY_OPT, true,
+                "Order returned entities by this field");
+        Option sortOrder = new Option(FalconCLIConstants.SORT_ORDER_OPT, true, "asc or desc order for results");
+        Option offset = new Option(FalconCLIConstants.OFFSET_OPT, true,
+                "Start returning entities from this offset");
+        Option numResults = new Option(FalconCLIConstants.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(FalconCLIConstants.SKIPDRYRUN_OPT, false, "skip dry run in workflow engine");
+        Option doAs = new Option(FalconCLIConstants.DO_AS_OPT, true, "doAs user");
+        Option userProps = new Option(PROPS_OPT, true, "User supplied comma separated key value properties");
+        Option showScheduler = new Option(SHOWSCHEDULER_OPT, false, "To return the scheduler "
+                + "on which the entity is scheduled.");
+        Option debug = new Option(FalconCLIConstants.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);
+        entityOptions.addOption(showScheduler);
+
+        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(FalconCLIConstants.TYPE_OPT);
+        String entityName = commandLine.getOptionValue(FalconCLIConstants.ENTITY_NAME_OPT);
+        String filePath = commandLine.getOptionValue(FalconCLIConstants.FILE_PATH_OPT);
+        String colo = commandLine.getOptionValue(FalconCLIConstants.COLO_OPT);
+        colo = getColo(colo);
+        String cluster = commandLine.getOptionValue(FalconCLIConstants.CLUSTER_OPT);
+        String start = commandLine.getOptionValue(FalconCLIConstants.START_OPT);
+        String end = commandLine.getOptionValue(FalconCLIConstants.END_OPT);
+        String orderBy = commandLine.getOptionValue(FalconCLIConstants.ORDER_BY_OPT);
+        String sortOrder = commandLine.getOptionValue(FalconCLIConstants.SORT_ORDER_OPT);
+        String filterBy = commandLine.getOptionValue(FalconCLIConstants.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(FalconCLIConstants.OFFSET_OPT), 0, "offset");
+        Integer numResults = parseIntegerInput(commandLine.getOptionValue(FalconCLIConstants.NUM_RESULTS_OPT),
+                null, "numResults");
+        String doAsUser = commandLine.getOptionValue(FalconCLIConstants.DO_AS_OPT);
+
+        Integer numInstances = parseIntegerInput(commandLine.getOptionValue(NUM_INSTANCES_OPT), 7, "numInstances");
+        Boolean skipDryRun = null;
+        if (optionsList.contains(FalconCLIConstants.SKIPDRYRUN_OPT)) {
+            skipDryRun = true;
+        }
+
+        String userProps = commandLine.getOptionValue(PROPS_OPT);
+        boolean showScheduler = false;
+        if (optionsList.contains(SHOWSCHEDULER_OPT)) {
+            showScheduler = true;
+        }
+
+        EntityType entityTypeEnum = null;
+        if (optionsList.contains(FalconCLIConstants.LIST_OPT)) {
+            if (entityType == null) {
+                entityType = "";
+            }
+            if (StringUtils.isNotEmpty(entityType)) {
+                String[] types = entityType.split(",");
+                for (String type : types) {
+                    EntityType.getEnum(type);
+                }
+            }
+        } else {
+            validateNotEmpty(entityType, FalconCLIConstants.TYPE_OPT);
+            entityTypeEnum = EntityType.getEnum(entityType);
+        }
+        validateSortOrder(sortOrder);
+        String entityAction = "entity";
+
+        if (optionsList.contains(SLA_MISS_ALERT_OPT)) {
+            validateNotEmpty(entityType, FalconCLIConstants.TYPE_OPT);
+            validateNotEmpty(start, FalconCLIConstants.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, FalconCLIConstants.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(FalconCLIConstants.SCHEDULE_OPT)) {
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            colo = getColo(colo);
+            result = client.schedule(entityTypeEnum, entityName, colo, skipDryRun, doAsUser, userProps).getMessage();
+        } else if (optionsList.contains(FalconCLIConstants.SUSPEND_OPT)) {
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            colo = getColo(colo);
+            result = client.suspend(entityTypeEnum, entityName, colo, doAsUser).getMessage();
+        } else if (optionsList.contains(FalconCLIConstants.RESUME_OPT)) {
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            colo = getColo(colo);
+            result = client.resume(entityTypeEnum, entityName, colo, doAsUser).getMessage();
+        } else if (optionsList.contains(DELETE_OPT)) {
+            validateColo(optionsList);
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            result = client.delete(entityTypeEnum, entityName, doAsUser).getMessage();
+        } else if (optionsList.contains(FalconCLIConstants.STATUS_OPT)) {
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            colo = getColo(colo);
+            result = client.getStatus(entityTypeEnum, entityName, colo, doAsUser, showScheduler).getMessage();
+        } else if (optionsList.contains(DEFINITION_OPT)) {
+            validateColo(optionsList);
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            result = client.getDefinition(entityType, entityName, doAsUser).toString();
+        } else if (optionsList.contains(FalconCLIConstants.DEPENDENCY_OPT)) {
+            validateColo(optionsList);
+            validateNotEmpty(entityName, FalconCLIConstants.ENTITY_NAME_OPT);
+            result = client.getDependency(entityType, entityName, doAsUser).toString();
+        } else if (optionsList.contains(FalconCLIConstants.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(FalconCLIConstants.SUMMARY_OPT)) {
+            validateEntityTypeForSummary(entityType);
+            validateNotEmpty(cluster, FalconCLIConstants.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, FalconCLIConstants.ENTITY_NAME_OPT);
+            colo = getColo(colo);
+            result = client.touch(entityType, entityName, colo, skipDryRun, doAsUser).getMessage();
+        } else if (optionsList.contains(FalconCLIConstants.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(FalconCLIConstants.COLO_OPT)) {
+            throw new FalconCLIException("Invalid argument : " + FalconCLIConstants.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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
----------------------------------------------------------------------
diff --git a/cli/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java b/cli/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
new file mode 100644
index 0000000..afbba12
--- /dev/null
+++ b/cli/src/main/java/org/apache/falcon/cli/FalconInstanceCLI.java
@@ -0,0 +1,340 @@
+/**
+ * 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.falcon.FalconCLIConstants;
+import org.apache.falcon.LifeCycle;
+import org.apache.falcon.ResponseHelper;
+import org.apache.falcon.client.FalconCLIException;
+import org.apache.falcon.client.FalconClient;
+import org.apache.falcon.resource.InstanceDependencyResult;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Instance extension to Falcon Command Line Interface - wraps the RESTful API for instances.
+ */
+public class FalconInstanceCLI extends FalconCLI {
+
+    private static final String FORCE_RERUN_FLAG = "force";
+    private static final String INSTANCE_TIME_OPT = "instanceTime";
+    private static final String RUNNING_OPT = "running";
+    private static final String KILL_OPT = "kill";
+    private static final String RERUN_OPT = "rerun";
+    private static final String LOG_OPT = "logs";
+    private static final String ALL_ATTEMPTS = "allAttempts";
+    private static final String RUNID_OPT = "runid";
+    private static final String CLUSTERS_OPT = "clusters";
+    private static final String SOURCECLUSTER_OPT = "sourceClusters";
+    private static final String LIFECYCLE_OPT = "lifecycle";
+    private static final String PARARMS_OPT = "params";
+    private static final String LISTING_OPT = "listing";
+    private static final String TRIAGE_OPT = "triage";
+
+    public FalconInstanceCLI() throws Exception {
+        super();
+    }
+
+    public Options createInstanceOptions() {
+
+        Options instanceOptions = new Options();
+
+        Option running = new Option(RUNNING_OPT, false,
+                "Gets running process instances for a given process");
+        Option list = new Option(FalconCLIConstants.LIST_OPT, false,
+                "Gets all instances for a given process in the range start time and optional end time");
+        Option status = new Option(FalconCLIConstants.STATUS_OPT, false,
+                "Gets status of process instances for a given process in the range start time and optional end time");
+        Option summary = new Option(FalconCLIConstants.SUMMARY_OPT, false,
+                "Gets summary of instances for a given process in the range start time and optional end time");
+        Option kill = new Option(KILL_OPT, false,
+                "Kills active process instances for a given process in the range start time and optional end time");
+        Option suspend = new Option(FalconCLIConstants.SUSPEND_OPT, false,
+                "Suspends active process instances for a given process in the range start time and optional end time");
+        Option resume = new Option(FalconCLIConstants.RESUME_OPT, false,
+                "Resumes suspended process instances for a given process "
+                        + "in the range start time and optional end time");
+        Option rerun = new Option(RERUN_OPT, false,
+                "Reruns process instances for a given process in the range start time and "
+                        + "optional end time and overrides properties present in job.properties file");
+        Option logs = new Option(LOG_OPT, false,
+                "Logs print the logs for process instances for a given process in "
+                        + "the range start time and optional end time");
+        Option params = new Option(PARARMS_OPT, false,
+                "Displays the workflow parameters for a given instance of specified nominal time"
+                        + "start time represents nominal time and end time is not considered");
+        Option listing = new Option(LISTING_OPT, false,
+                "Displays feed listing and their status between a start and end time range.");
+        Option dependency = new Option(FalconCLIConstants.DEPENDENCY_OPT, false,
+                "Displays dependent instances for a specified instance.");
+        Option triage = new Option(TRIAGE_OPT, false,
+                "Triage a feed or process instance and find the failures in it's lineage.");
+
+        OptionGroup group = new OptionGroup();
+        group.addOption(running);
+        group.addOption(list);
+        group.addOption(status);
+        group.addOption(summary);
+        group.addOption(kill);
+        group.addOption(resume);
+        group.addOption(suspend);
+        group.addOption(resume);
+        group.addOption(rerun);
+        group.addOption(logs);
+        group.addOption(params);
+        group.addOption(listing);
+        group.addOption(dependency);
+        group.addOption(triage);
+
+        Option url = new Option(FalconCLIConstants.URL_OPTION, true, "Falcon URL");
+        Option start = new Option(FalconCLIConstants.START_OPT, true,
+                "Start time is required for commands, status, kill, suspend, resume and re-run"
+                        + "and it is nominal time while displaying workflow params");
+        Option end = new Option(FalconCLIConstants.END_OPT, true,
+                "End time is optional for commands, status, kill, suspend, resume and re-run; "
+                        + "if not specified then current time is considered as end time");
+        Option runid = new Option(RUNID_OPT, true,
+                "Instance runid  is optional and user can specify the runid, defaults to 0");
+        Option clusters = new Option(CLUSTERS_OPT, true,
+                "clusters is optional for commands kill, suspend and resume, "
+                        + "should not be specified for other commands");
+        Option sourceClusters = new Option(SOURCECLUSTER_OPT, true,
+                " source cluster is optional for commands kill, suspend and resume, "
+                        + "should not be specified for other commands (required for only feed)");
+        Option filePath = new Option(FalconCLIConstants.FILE_PATH_OPT, true,
+                "Path to job.properties file is required for rerun command, "
+                        + "it should contain name=value pair for properties to override for rerun");
+        Option entityType = new Option(FalconCLIConstants.TYPE_OPT, true,
+                "Entity type, can be feed or process xml");
+        Option entityName = new Option(FalconCLIConstants.ENTITY_NAME_OPT, true,
+                "Entity name, can be feed or process name");
+        Option colo = new Option(FalconCLIConstants.COLO_OPT, true,
+                "Colo on which the cmd has to be executed");
+        Option lifecycle = new Option(LIFECYCLE_OPT, true,
+                "describes life cycle of entity , for feed it can be replication/retention "
+                        + "and for process it can be execution");
+        Option filterBy = new Option(FalconCLIConstants.FILTER_BY_OPT, true,
+                "Filter returned instances by the specified fields");
+        Option orderBy = new Option(FalconCLIConstants.ORDER_BY_OPT, true,
+                "Order returned instances by this field");
+        Option sortOrder = new Option(FalconCLIConstants.SORT_ORDER_OPT, true, "asc or desc order for results");
+        Option offset = new Option(FalconCLIConstants.OFFSET_OPT, true,
+                "Start returning instances from this offset");
+        Option numResults = new Option(FalconCLIConstants.NUM_RESULTS_OPT, true,
+                "Number of results to return per request");
+        Option forceRerun = new Option(FORCE_RERUN_FLAG, false,
+                "Flag to forcefully rerun entire workflow of an instance");
+        Option doAs = new Option(FalconCLIConstants.DO_AS_OPT, true, "doAs user");
+        Option debug = new Option(FalconCLIConstants.DEBUG_OPTION, false, "Use debug mode to see"
+                + " debugging statements on stdout");
+
+        Option instanceTime = new Option(INSTANCE_TIME_OPT, true, "Time for an instance");
+
+        Option allAttempts = new Option(ALL_ATTEMPTS, false, "To get all attempts of corresponding instances");
+
+        instanceOptions.addOption(url);
+        instanceOptions.addOptionGroup(group);
+        instanceOptions.addOption(start);
+        instanceOptions.addOption(end);
+        instanceOptions.addOption(filePath);
+        instanceOptions.addOption(entityType);
+        instanceOptions.addOption(entityName);
+        instanceOptions.addOption(runid);
+        instanceOptions.addOption(clusters);
+        instanceOptions.addOption(sourceClusters);
+        instanceOptions.addOption(colo);
+        instanceOptions.addOption(lifecycle);
+        instanceOptions.addOption(filterBy);
+        instanceOptions.addOption(offset);
+        instanceOptions.addOption(orderBy);
+        instanceOptions.addOption(sortOrder);
+        instanceOptions.addOption(numResults);
+        instanceOptions.addOption(forceRerun);
+        instanceOptions.addOption(doAs);
+        instanceOptions.addOption(debug);
+        instanceOptions.addOption(instanceTime);
+        instanceOptions.addOption(allAttempts);
+
+        return instanceOptions;
+    }
+
+    public void instanceCommand(CommandLine commandLine, FalconClient client) throws FalconCLIException, IOException {
+        Set<String> optionsList = new HashSet<String>();
+        for (Option option : commandLine.getOptions()) {
+            optionsList.add(option.getOpt());
+        }
+
+        String result;
+        String type = commandLine.getOptionValue(FalconCLIConstants.TYPE_OPT);
+        String entity = commandLine.getOptionValue(FalconCLIConstants.ENTITY_NAME_OPT);
+        String instanceTime = commandLine.getOptionValue(INSTANCE_TIME_OPT);
+        String start = commandLine.getOptionValue(FalconCLIConstants.START_OPT);
+        String end = commandLine.getOptionValue(FalconCLIConstants.END_OPT);
+        String filePath = commandLine.getOptionValue(FalconCLIConstants.FILE_PATH_OPT);
+        String runId = commandLine.getOptionValue(RUNID_OPT);
+        String colo = commandLine.getOptionValue(FalconCLIConstants.COLO_OPT);
+        String clusters = commandLine.getOptionValue(CLUSTERS_OPT);
+        String sourceClusters = commandLine.getOptionValue(SOURCECLUSTER_OPT);
+        List<LifeCycle> lifeCycles = getLifeCycle(commandLine.getOptionValue(LIFECYCLE_OPT));
+        String filterBy = commandLine.getOptionValue(FalconCLIConstants.FILTER_BY_OPT);
+        String orderBy = commandLine.getOptionValue(FalconCLIConstants.ORDER_BY_OPT);
+        String sortOrder = commandLine.getOptionValue(FalconCLIConstants.SORT_ORDER_OPT);
+        String doAsUser = commandLine.getOptionValue(FalconCLIConstants.DO_AS_OPT);
+        Integer offset = parseIntegerInput(commandLine.getOptionValue(FalconCLIConstants.OFFSET_OPT), 0, "offset");
+        Integer numResults = parseIntegerInput(commandLine.getOptionValue(FalconCLIConstants.NUM_RESULTS_OPT),
+                null, "numResults");
+
+        colo = getColo(colo);
+        String instanceAction = "instance";
+        validateSortOrder(sortOrder);
+        validateInstanceCommands(optionsList, entity, type, colo);
+
+        if (optionsList.contains(TRIAGE_OPT)) {
+            validateNotEmpty(colo, FalconCLIConstants.COLO_OPT);
+            validateNotEmpty(start, FalconCLIConstants.START_OPT);
+            validateNotEmpty(type, FalconCLIConstants.TYPE_OPT);
+            validateEntityTypeForSummary(type);
+            validateNotEmpty(entity, FalconCLIConstants.ENTITY_NAME_OPT);
+            result = client.triage(type, entity, start, colo).toString();
+        } else if (optionsList.contains(FalconCLIConstants.DEPENDENCY_OPT)) {
+            validateNotEmpty(instanceTime, INSTANCE_TIME_OPT);
+            InstanceDependencyResult response = client.getInstanceDependencies(type, entity, instanceTime, colo);
+            result = ResponseHelper.getString(response);
+
+        } else if (optionsList.contains(RUNNING_OPT)) {
+            validateOrderBy(orderBy, instanceAction);
+            validateFilterBy(filterBy, instanceAction);
+            result = ResponseHelper.getString(client.getRunningInstances(type,
+                    entity, colo, lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser));
+        } else if (optionsList.contains(FalconCLIConstants.STATUS_OPT)
+                || optionsList.contains(FalconCLIConstants.LIST_OPT)) {
+            boolean allAttempts = false;
+            if (optionsList.contains(ALL_ATTEMPTS)) {
+                allAttempts = true;
+            }
+            validateOrderBy(orderBy, instanceAction);
+            validateFilterBy(filterBy, instanceAction);
+            result = ResponseHelper.getString(client.getStatusOfInstances(type, entity, start, end, colo,
+                    lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser, allAttempts));
+        } else if (optionsList.contains(FalconCLIConstants.SUMMARY_OPT)) {
+            validateOrderBy(orderBy, "summary");
+            validateFilterBy(filterBy, "summary");
+            result = ResponseHelper.getString(client.getSummaryOfInstances(type, entity, start, end, colo,
+                    lifeCycles, filterBy, orderBy, sortOrder, doAsUser));
+        } else if (optionsList.contains(KILL_OPT)) {
+            validateNotEmpty(start, FalconCLIConstants.START_OPT);
+            validateNotEmpty(end, FalconCLIConstants.END_OPT);
+            result = ResponseHelper.getString(client.killInstances(type, entity, start, end, colo, clusters,
+                    sourceClusters, lifeCycles, doAsUser));
+        } else if (optionsList.contains(FalconCLIConstants.SUSPEND_OPT)) {
+            validateNotEmpty(start, FalconCLIConstants.START_OPT);
+            validateNotEmpty(end, FalconCLIConstants.END_OPT);
+            result = ResponseHelper.getString(client.suspendInstances(type, entity, start, end, colo, clusters,
+                    sourceClusters, lifeCycles, doAsUser));
+        } else if (optionsList.contains(FalconCLIConstants.RESUME_OPT)) {
+            validateNotEmpty(start, FalconCLIConstants.START_OPT);
+            validateNotEmpty(end, FalconCLIConstants.END_OPT);
+            result = ResponseHelper.getString(client.resumeInstances(type, entity, start, end, colo, clusters,
+                    sourceClusters, lifeCycles, doAsUser));
+        } else if (optionsList.contains(RERUN_OPT)) {
+            validateNotEmpty(start, FalconCLIConstants.START_OPT);
+            validateNotEmpty(end, FalconCLIConstants.END_OPT);
+            boolean isForced = false;
+            if (optionsList.contains(FORCE_RERUN_FLAG)) {
+                isForced = true;
+            }
+            result = ResponseHelper.getString(client.rerunInstances(type, entity, start, end, filePath, colo,
+                    clusters, sourceClusters, lifeCycles, isForced, doAsUser));
+        } else if (optionsList.contains(LOG_OPT)) {
+            validateOrderBy(orderBy, instanceAction);
+            validateFilterBy(filterBy, instanceAction);
+            result = ResponseHelper.getString(client.getLogsOfInstances(type, entity, start, end, colo, runId,
+                    lifeCycles, filterBy, orderBy, sortOrder, offset, numResults, doAsUser), runId);
+        } else if (optionsList.contains(PARARMS_OPT)) {
+            // start time is the nominal time of instance
+            result = ResponseHelper.getString(client.getParamsOfInstance(type, entity,
+                    start, colo, lifeCycles, doAsUser));
+        } else if (optionsList.contains(LISTING_OPT)) {
+            result = ResponseHelper.getString(client.getFeedInstanceListing(type, entity, start, end, colo, doAsUser));
+        } else {
+            throw new FalconCLIException("Invalid command");
+        }
+
+        OUT.get().println(result);
+    }
+
+    private void validateInstanceCommands(Set<String> optionsList,
+                                          String entity, String type,
+                                          String colo) throws FalconCLIException {
+
+        validateNotEmpty(entity, FalconCLIConstants.ENTITY_NAME_OPT);
+        validateNotEmpty(type, FalconCLIConstants.TYPE_OPT);
+        validateNotEmpty(colo, FalconCLIConstants.COLO_OPT);
+
+        if (optionsList.contains(CLUSTERS_OPT)) {
+            if (optionsList.contains(RUNNING_OPT)
+                    || optionsList.contains(LOG_OPT)
+                    || optionsList.contains(FalconCLIConstants.STATUS_OPT)
+                    || optionsList.contains(FalconCLIConstants.SUMMARY_OPT)) {
+                throw new FalconCLIException("Invalid argument: clusters");
+            }
+        }
+
+        if (optionsList.contains(SOURCECLUSTER_OPT)) {
+            if (optionsList.contains(RUNNING_OPT)
+                    || optionsList.contains(LOG_OPT)
+                    || optionsList.contains(FalconCLIConstants.STATUS_OPT)
+                    || optionsList.contains(FalconCLIConstants.SUMMARY_OPT) || !type.equals("feed")) {
+                throw new FalconCLIException("Invalid argument: sourceClusters");
+            }
+        }
+
+        if (optionsList.contains(FORCE_RERUN_FLAG)) {
+            if (!optionsList.contains(RERUN_OPT)) {
+                throw new FalconCLIException("Force option can be used only with instance rerun");
+            }
+        }
+    }
+
+    private List<LifeCycle> getLifeCycle(String lifeCycleValue) throws FalconCLIException {
+
+        if (lifeCycleValue != null) {
+            String[] lifeCycleValues = lifeCycleValue.split(",");
+            List<LifeCycle> lifeCycles = new ArrayList<LifeCycle>();
+            try {
+                for (String lifeCycle : lifeCycleValues) {
+                    lifeCycles.add(LifeCycle.valueOf(lifeCycle.toUpperCase().trim()));
+                }
+            } catch (IllegalArgumentException e) {
+                throw new FalconCLIException("Invalid life cycle values: " + lifeCycles, e);
+            }
+            return lifeCycles;
+        }
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/cli/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
----------------------------------------------------------------------
diff --git a/cli/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java b/cli/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
new file mode 100644
index 0000000..b3e138f
--- /dev/null
+++ b/cli/src/main/java/org/apache/falcon/cli/FalconMetadataCLI.java
@@ -0,0 +1,256 @@
+/**
+ * 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.FalconCLIConstants;
+import org.apache.falcon.client.FalconCLIException;
+import org.apache.falcon.client.FalconClient;
+import org.apache.falcon.entity.v0.EntityType;
+import org.apache.falcon.metadata.RelationshipType;
+
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Metadata extension to Falcon Command Line Interface - wraps the RESTful API for Metadata.
+ */
+public class FalconMetadataCLI extends FalconCLI {
+
+    public static final AtomicReference<PrintStream> OUT = new AtomicReference<PrintStream>(System.out);
+
+    // Discovery Commands
+    public static final String DISCOVERY_OPT = "discovery";
+    public static final String LIST_OPT = "list";
+    public static final String URL_OPTION = "url";
+
+    // Lineage Commands
+    public static final String LINEAGE_OPT = "lineage";
+    public static final String VERTEX_CMD = "vertex";
+    public static final String VERTICES_CMD = "vertices";
+    public static final String VERTEX_EDGES_CMD = "edges";
+    public static final String EDGE_CMD = "edge";
+    public static final String ID_OPT = "id";
+    public static final String KEY_OPT = "key";
+    public static final String VALUE_OPT = "value";
+    public static final String DIRECTION_OPT = "direction";
+
+    public FalconMetadataCLI() throws Exception {
+        super();
+    }
+
+    public Options createMetadataOptions() {
+        Options metadataOptions = new Options();
+
+        OptionGroup group = new OptionGroup();
+        Option discovery = new Option(DISCOVERY_OPT, false, "Discover falcon metadata relations");
+        Option lineage = new Option(LINEAGE_OPT, false, "Get falcon metadata lineage information");
+        group.addOption(discovery);
+        group.addOption(lineage);
+        Option pipeline = new Option(FalconCLIConstants.PIPELINE_OPT, true,
+                "Get lineage graph for the entities in a pipeline");
+        metadataOptions.addOptionGroup(group);
+
+        // Add discovery options
+
+        Option list = new Option(LIST_OPT, false, "List all dimensions");
+        Option relations = new Option(FalconCLIConstants.RELATIONS_OPT, false, "List all relations for a dimension");
+        metadataOptions.addOption(list);
+        metadataOptions.addOption(relations);
+
+        Option url = new Option(URL_OPTION, true, "Falcon URL");
+        Option type = new Option(FalconCLIConstants.TYPE_OPT, true, "Dimension type");
+        Option name = new Option(FalconCLIConstants.NAME_OPT, true, "Dimension name");
+        Option cluster = new Option(FalconCLIConstants.CLUSTER_OPT, true, "Cluster name");
+        Option feed = new Option(FalconCLIConstants.FEED_OPT, true, "Feed Entity name");
+        Option process = new Option(FalconCLIConstants.PROCESS_OPT, true, "Process Entity name");
+        Option numResults = new Option(FalconCLIConstants.NUM_RESULTS_OPT, true,
+                "Number of results to return per request");
+
+        // Add lineage options
+        metadataOptions.addOption(pipeline);
+
+        metadataOptions.addOption(url);
+        metadataOptions.addOption(type);
+        metadataOptions.addOption(cluster);
+        metadataOptions.addOption(name);
+        metadataOptions.addOption(feed);
+        metadataOptions.addOption(process);
+        metadataOptions.addOption(numResults);
+
+        Option vertex = new Option(VERTEX_CMD, false, "show the vertices");
+        Option vertices = new Option(VERTICES_CMD, false, "show the vertices");
+        Option vertexEdges = new Option(VERTEX_EDGES_CMD, false, "show the edges for a given vertex");
+        Option edges = new Option(EDGE_CMD, false, "show the edges");
+        Option id = new Option(ID_OPT, true, "vertex or edge id");
+        Option key = new Option(KEY_OPT, true, "key property");
+        Option value = new Option(VALUE_OPT, true, "value property");
+        Option direction = new Option(DIRECTION_OPT, true, "edge direction property");
+        Option debug = new Option(FalconCLIConstants.DEBUG_OPTION, false,
+                "Use debug mode to see debugging statements on stdout");
+
+        metadataOptions.addOption(vertex);
+        metadataOptions.addOption(vertices);
+        metadataOptions.addOption(vertexEdges);
+        metadataOptions.addOption(edges);
+        metadataOptions.addOption(id);
+        metadataOptions.addOption(key);
+        metadataOptions.addOption(value);
+        metadataOptions.addOption(direction);
+        metadataOptions.addOption(debug);
+
+        Option doAs = new Option(FalconCLIConstants.DO_AS_OPT, true, "doAs user");
+        metadataOptions.addOption(doAs);
+
+        return metadataOptions;
+    }
+
+    public void metadataCommand(CommandLine commandLine, FalconClient client) throws FalconCLIException {
+        Set<String> optionsList = new HashSet<String>();
+        for (Option option : commandLine.getOptions()) {
+            optionsList.add(option.getOpt());
+        }
+
+        String result;
+        String dimensionType = commandLine.getOptionValue(FalconCLIConstants.TYPE_OPT);
+        String cluster = commandLine.getOptionValue(FalconCLIConstants.CLUSTER_OPT);
+        String feed = commandLine.getOptionValue(FalconCLIConstants.FEED_OPT);
+        String process = commandLine.getOptionValue(FalconCLIConstants.PROCESS_OPT);
+        String dimensionName = commandLine.getOptionValue(FalconCLIConstants.NAME_OPT);
+        String id = commandLine.getOptionValue(ID_OPT);
+        String key = commandLine.getOptionValue(KEY_OPT);
+        String value = commandLine.getOptionValue(VALUE_OPT);
+        String direction = commandLine.getOptionValue(DIRECTION_OPT);
+        String pipeline = commandLine.getOptionValue(FalconCLIConstants.PIPELINE_OPT);
+        String doAsUser = commandLine.getOptionValue(FalconCLIConstants.DO_AS_OPT);
+        Integer numResults = parseIntegerInput(commandLine.getOptionValue(FalconCLIConstants.NUM_RESULTS_OPT),
+                null, "numResults");
+
+        if (optionsList.contains(LINEAGE_OPT)) {
+            validatePipelineName(pipeline);
+            result = client.getEntityLineageGraph(pipeline, doAsUser).getDotNotation();
+        } else if (optionsList.contains(LIST_OPT)) {
+            validateDimensionType(dimensionType.toUpperCase());
+            if (!(dimensionType.toUpperCase())
+                    .equals(RelationshipType.REPLICATION_METRICS.name())) {
+                result = client.getDimensionList(dimensionType, cluster, doAsUser);
+            } else {
+                String schedEntityType = null;
+                String schedEntityName = null;
+                if (StringUtils.isNotEmpty(feed)) {
+                    schedEntityType = EntityType.getEnum(FalconCLIConstants.FEED_OPT).name();
+                    schedEntityName = feed;
+                } else if (StringUtils.isNotEmpty(process)) {
+                    schedEntityType = EntityType.getEnum(FalconCLIConstants.PROCESS_OPT).name();
+                    schedEntityName = process;
+                }
+                validateScheduleEntity(schedEntityType, schedEntityName);
+
+                result = client.getReplicationMetricsDimensionList(schedEntityType, schedEntityName,
+                        numResults, doAsUser);
+            }
+        } else if (optionsList.contains(FalconCLIConstants.RELATIONS_OPT)) {
+            validateDimensionType(dimensionType.toUpperCase());
+            validateDimensionName(dimensionName, FalconCLIConstants.RELATIONS_OPT);
+            result = client.getDimensionRelations(dimensionType, dimensionName, doAsUser);
+        } else if (optionsList.contains(VERTEX_CMD)) {
+            validateId(id);
+            result = client.getVertex(id, doAsUser);
+        } else if (optionsList.contains(VERTICES_CMD)) {
+            validateVerticesCommand(key, value);
+            result = client.getVertices(key, value, doAsUser);
+        } else if (optionsList.contains(VERTEX_EDGES_CMD)) {
+            validateVertexEdgesCommand(id, direction);
+            result = client.getVertexEdges(id, direction, doAsUser);
+        } else if (optionsList.contains(EDGE_CMD)) {
+            validateId(id);
+            result = client.getEdge(id, doAsUser);
+        } else {
+            throw new FalconCLIException("Invalid metadata command");
+        }
+
+        OUT.get().println(result);
+    }
+
+    private void validatePipelineName(String pipeline) throws FalconCLIException {
+        if (StringUtils.isEmpty(pipeline)) {
+            throw new FalconCLIException("Invalid value for pipeline");
+        }
+    }
+
+    private void validateDimensionType(String dimensionType) throws FalconCLIException {
+        if (StringUtils.isEmpty(dimensionType)
+                ||  dimensionType.contains("INSTANCE")) {
+            throw new FalconCLIException("Invalid value provided for queryParam \"type\" " + dimensionType);
+        }
+        try {
+            RelationshipType.valueOf(dimensionType);
+        } catch (IllegalArgumentException iae) {
+            throw new FalconCLIException("Invalid value provided for queryParam \"type\" " + dimensionType);
+        }
+    }
+
+    private void validateDimensionName(String dimensionName, String action) throws FalconCLIException {
+        if (StringUtils.isEmpty(dimensionName)) {
+            throw new FalconCLIException("Dimension ID cannot be empty or null for action " + action);
+        }
+    }
+
+    private void validateScheduleEntity(String schedEntityType, String schedEntityName) throws FalconCLIException {
+        if (StringUtils.isBlank(schedEntityType)) {
+            throw new FalconCLIException("Entity must be schedulable type : -feed/process");
+        }
+
+        if (StringUtils.isBlank(schedEntityName)) {
+            throw new FalconCLIException("Entity name is missing");
+        }
+    }
+
+    private void validateId(String id) throws FalconCLIException {
+        if (id == null || id.length() == 0) {
+            throw new FalconCLIException("Missing argument: id");
+        }
+    }
+
+    private void validateVerticesCommand(String key, String value) throws FalconCLIException {
+        if (key == null || key.length() == 0) {
+            throw new FalconCLIException("Missing argument: key");
+        }
+
+        if (value == null || value.length() == 0) {
+            throw new FalconCLIException("Missing argument: value");
+        }
+    }
+
+    private void validateVertexEdgesCommand(String id, String direction) throws FalconCLIException {
+        if (id == null || id.length() == 0) {
+            throw new FalconCLIException("Missing argument: id");
+        }
+
+        if (direction == null || direction.length() == 0) {
+            throw new FalconCLIException("Missing argument: direction");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/FalconCLIConstants.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/FalconCLIConstants.java b/client/src/main/java/org/apache/falcon/FalconCLIConstants.java
new file mode 100644
index 0000000..eb4cf3f
--- /dev/null
+++ b/client/src/main/java/org/apache/falcon/FalconCLIConstants.java
@@ -0,0 +1,76 @@
+/**
+ * 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;
+
+/**
+* FalconCLI Constants.
+*/
+public final class FalconCLIConstants {
+    private FalconCLIConstants(){
+
+    }
+    public static final String ENV_FALCON_DEBUG = "FALCON_DEBUG";
+    public static final String DEBUG_OPTION = "debug";
+    public static final String URL_OPTION = "url";
+
+    public static final String ADMIN_CMD = "admin";
+    public static final String HELP_CMD = "help";
+    public static final String METADATA_CMD = "metadata";
+    public static final String ENTITY_CMD = "entity";
+    public static final String INSTANCE_CMD = "instance";
+    public static final String RECIPE_CMD = "recipe";
+
+    public static final String TYPE_OPT = "type";
+    public static final String COLO_OPT = "colo";
+    public static final String CLUSTER_OPT = "cluster";
+    public static final String FEED_OPT = "feed";
+    public static final String PROCESS_OPT = "process";
+    public static final String ENTITY_NAME_OPT = "name";
+    public static final String FILE_PATH_OPT = "file";
+    public static final String VERSION_OPT = "version";
+    public static final String SCHEDULE_OPT = "schedule";
+    public static final String SUSPEND_OPT = "suspend";
+    public static final String RESUME_OPT = "resume";
+    public static final String STATUS_OPT = "status";
+    public static final String SUMMARY_OPT = "summary";
+    public static final String DEPENDENCY_OPT = "dependency";
+    public static final String LIST_OPT = "list";
+    public static final String SKIPDRYRUN_OPT = "skipDryRun";
+    public static final String FILTER_BY_OPT = "filterBy";
+    public static final String ORDER_BY_OPT = "orderBy";
+    public static final String SORT_ORDER_OPT = "sortOrder";
+    public static final String OFFSET_OPT = "offset";
+    public static final String NUM_RESULTS_OPT = "numResults";
+    public static final String START_OPT = "start";
+    public static final String END_OPT = "end";
+    public static final String CURRENT_COLO = "current.colo";
+    public static final String CLIENT_PROPERTIES = "/client.properties";
+    public static final String DO_AS_OPT = "doAs";
+    public static final String RELATIONS_OPT = "relations";
+    public static final String PIPELINE_OPT = "pipeline";
+    public static final String NAME_OPT = "name";
+
+    /**
+     * Recipe operation enum.
+     */
+    public enum RecipeOperation {
+        HDFS_REPLICATION,
+        HIVE_DISASTER_RECOVERY
+    }
+}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/CLIParser.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/CLIParser.java b/client/src/main/java/org/apache/falcon/cli/CLIParser.java
deleted file mode 100644
index 9d8554f..0000000
--- a/client/src/main/java/org/apache/falcon/cli/CLIParser.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/**
- * 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.GnuParser;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.apache.commons.cli.HelpFormatter;
-
-import java.io.PrintWriter;
-import java.text.MessageFormat;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-
-/**
- * Cannibalized from Oozie CLIParser into Falcon
- * Command line parser based on Apache common-cli 1.x that supports subcommands.
- */
-public class CLIParser {
-    private static final String LEFT_PADDING = "      ";
-
-    private String cliName;
-    private String[] cliHelp;
-    private Map<String, Options> commands = new LinkedHashMap<String, Options>();
-    private Map<String, Boolean> commandWithArgs = new LinkedHashMap<String, Boolean>();
-    private Map<String, String> commandsHelp = new LinkedHashMap<String, String>();
-
-    /**
-     * Create a parser.
-     *
-     * @param aCliName name of the parser, for help purposes.
-     * @param aCliHelp help for the CLI.
-     */
-    public CLIParser(String aCliName, String[] aCliHelp) {
-        this.cliName = aCliName;
-        this.cliHelp = aCliHelp.clone();
-    }
-
-    /**
-     * Add a command to the parser.
-     *
-     * @param command        comand name.
-     * @param argsHelp       command arguments help.
-     * @param commandHelp    command description.
-     * @param commandOptions command options.
-     * @param hasArguments   has args
-     */
-    public void addCommand(String command, String argsHelp, String commandHelp, Options commandOptions,
-                           boolean hasArguments) {
-        String helpMsg = argsHelp + ((hasArguments) ? "<ARGS> " : "") + ": " + commandHelp;
-        commandsHelp.put(command, helpMsg);
-        commands.put(command, commandOptions);
-        commandWithArgs.put(command, hasArguments);
-    }
-
-    /**
-     * Bean that represents a parsed command.
-     */
-    public static final class Command {
-        private String name;
-        private CommandLine commandLine;
-
-        private Command(String name, CommandLine commandLine) {
-            this.name = name;
-            this.commandLine = commandLine;
-        }
-
-        /**
-         * Return the command name.
-         *
-         * @return the command name.
-         */
-        public String getName() {
-            return name;
-        }
-
-        /**
-         * Return the command line.
-         *
-         * @return the command line.
-         */
-        public CommandLine getCommandLine() {
-            return commandLine;
-        }
-    }
-
-    /**
-     * Parse a array of arguments into a command.
-     *
-     * @param args array of arguments.
-     * @return the parsed Command.
-     * @throws ParseException thrown if the arguments could not be parsed.
-     */
-    public Command parse(String[] args) throws ParseException {
-        if (args.length == 0) {
-            throw new ParseException("missing sub-command");
-        } else {
-            if (commands.containsKey(args[0])) {
-                GnuParser parser = new GnuParser();
-                String[] minusCommand = new String[args.length - 1];
-                System.arraycopy(args, 1, minusCommand, 0, minusCommand.length);
-                return new Command(args[0], parser.parse(commands.get(args[0]), minusCommand,
-                        commandWithArgs.get(args[0])));
-            } else {
-                throw new ParseException(MessageFormat.format("invalid sub-command [{0}]", args[0]));
-            }
-        }
-    }
-
-    public String shortHelp() {
-        return "use 'help' sub-command for help details";
-    }
-
-    /**
-     * Print the help for the parser to standard output.
-     */
-    public void showHelp() {
-        PrintWriter pw = new PrintWriter(System.out);
-        pw.println("usage: ");
-        for (String s : cliHelp) {
-            pw.println(LEFT_PADDING + s);
-        }
-        pw.println();
-        HelpFormatter formatter = new HelpFormatter();
-        for (Map.Entry<String, Options> entry : commands.entrySet()) {
-            String s = LEFT_PADDING + cliName + " " + entry.getKey() + " ";
-            if (entry.getValue().getOptions().size() > 0) {
-                pw.println(s + "<OPTIONS> " + commandsHelp.get(entry.getKey()));
-                formatter.printOptions(pw, 100, entry.getValue(), s.length(), 3);
-            } else {
-                pw.println(s + commandsHelp.get(entry.getKey()));
-            }
-            pw.println();
-        }
-        pw.flush();
-    }
-}

http://git-wip-us.apache.org/repos/asf/falcon/blob/6655e90a/client/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java b/client/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
deleted file mode 100644
index 6360743..0000000
--- a/client/src/main/java/org/apache/falcon/cli/FalconAdminCLI.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * 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.falcon.client.FalconCLIException;
-import org.apache.falcon.client.FalconClient;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Admin extension to Falcon Command Line Interface - wraps the RESTful API for admin commands.
- */
-public class FalconAdminCLI extends FalconCLI {
-
-    private static final String STACK_OPTION = "stack";
-
-    public FalconAdminCLI() throws Exception {
-        super();
-    }
-
-    public Options createAdminOptions() {
-        Options adminOptions = new Options();
-        Option url = new Option(URL_OPTION, true, "Falcon URL");
-        adminOptions.addOption(url);
-
-        OptionGroup group = new OptionGroup();
-        Option status = new Option(STATUS_OPT, false,
-                "show the current system status");
-        Option version = new Option(VERSION_OPT, false,
-                "show Falcon server build version");
-        Option stack = new Option(STACK_OPTION, false,
-                "show the thread stack dump");
-        Option doAs = new Option(DO_AS_OPT, true,
-                "doAs user");
-        Option help = new Option("help", false, "show Falcon help");
-        Option debug = new Option(DEBUG_OPTION, false, "Use debug mode to see debugging statements on stdout");
-        group.addOption(status);
-        group.addOption(version);
-        group.addOption(stack);
-        group.addOption(help);
-
-        adminOptions.addOptionGroup(group);
-        adminOptions.addOption(doAs);
-        adminOptions.addOption(debug);
-        return adminOptions;
-    }
-
-    public int adminCommand(CommandLine commandLine, FalconClient client,
-                             String falconUrl) throws FalconCLIException, IOException {
-        String result;
-        Set<String> optionsList = new HashSet<String>();
-        for (Option option : commandLine.getOptions()) {
-            optionsList.add(option.getOpt());
-        }
-
-        String doAsUser = commandLine.getOptionValue(DO_AS_OPT);
-
-        if (optionsList.contains(STACK_OPTION)) {
-            result = client.getThreadDump(doAsUser);
-            OUT.get().println(result);
-        }
-
-        int exitValue = 0;
-        if (optionsList.contains(STATUS_OPT)) {
-            try {
-                int status = client.getStatus(doAsUser);
-                if (status != 200) {
-                    ERR.get().println("Falcon server is not fully operational (on " + falconUrl + "). "
-                            + "Please check log files.");
-                    exitValue = status;
-                } else {
-                    OUT.get().println("Falcon server is running (on " + falconUrl + ")");
-                }
-            } catch (Exception e) {
-                ERR.get().println("Falcon server doesn't seem to be running on " + falconUrl);
-                exitValue = -1;
-            }
-        } else if (optionsList.contains(VERSION_OPT)) {
-            result = client.getVersion(doAsUser);
-            OUT.get().println("Falcon server build version: " + result);
-        } else if (optionsList.contains(HELP_CMD)) {
-            OUT.get().println("Falcon Help");
-        }
-        return exitValue;
-    }
-
-}