/*
* Copyright © 2015 Cask Data, Inc.
*
* Licensed 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 co.cask.cdap.cli.command;
import co.cask.cdap.cli.ArgumentName;
import co.cask.cdap.cli.CLIConfig;
import co.cask.cdap.cli.Categorized;
import co.cask.cdap.cli.CommandCategory;
import co.cask.cdap.cli.ElementType;
import co.cask.cdap.cli.english.Article;
import co.cask.cdap.cli.english.Fragment;
import co.cask.cdap.cli.util.AbstractAuthCommand;
import co.cask.cdap.cli.util.FilePathResolver;
import co.cask.cdap.client.StreamClient;
import co.cask.cdap.proto.Id;
import co.cask.common.cli.Arguments;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.google.inject.Inject;
import java.io.File;
import java.io.PrintStream;
import java.util.Map;
/**
* Command for sending file to stream
*/
public class LoadStreamCommand extends AbstractAuthCommand implements Categorized {
// A map from file extension to content type
private static final Map<String, String> CONTENT_TYPE_MAP;
static {
Map<String, String> contentTypes = Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER);
contentTypes.put("avro", "avro/binary");
contentTypes.put("csv", "text/csv");
contentTypes.put("tsv", "text/tsv");
contentTypes.put("txt", "text/plain");
contentTypes.put("log", "text/plain");
CONTENT_TYPE_MAP = contentTypes;
}
private final StreamClient streamClient;
private final FilePathResolver resolver;
@Inject
public LoadStreamCommand(StreamClient streamClient, CLIConfig cliConfig, FilePathResolver resolver) {
super(cliConfig);
this.streamClient = streamClient;
this.resolver = resolver;
}
@Override
public void perform(Arguments arguments, PrintStream output) throws Exception {
Id.Stream streamId = Id.Stream.from(cliConfig.getCurrentNamespace(),
arguments.get(ArgumentName.STREAM.toString()));
File file = resolver.resolvePathToFile(arguments.get(ArgumentName.LOCAL_FILE_PATH.toString()));
String contentType = arguments.get(ArgumentName.CONTENT_TYPE.toString(), "");
if (!file.isFile()) {
throw new IllegalArgumentException("Not a file: " + file);
}
if (contentType.isEmpty()) {
contentType = getContentType(Files.getFileExtension(file.getName()));
}
if (contentType.isEmpty()) {
throw new IllegalArgumentException("Unsupported file format.");
}
streamClient.sendFile(streamId, contentType, file);
output.printf("Successfully loaded file to stream '%s'\n", streamId.getId());
}
@Override
public String getPattern() {
return String.format("load stream <%s> <%s> [<%s>]",
ArgumentName.STREAM, ArgumentName.LOCAL_FILE_PATH, ArgumentName.CONTENT_TYPE);
}
@Override
public String getDescription() {
return String.format("Loads a file to %s. The contents of the file will " +
"become multiple events in the %s, " +
"based on the content type (%s). If '<%s>' is not provided, " +
"it will be detected by the file extension. Supported file extensions: '%s'.",
Fragment.of(Article.A, ElementType.STREAM.getName()),
ElementType.STREAM.getName(),
Joiner.on(", ").join(ImmutableSet.copyOf(CONTENT_TYPE_MAP.values())),
ArgumentName.CONTENT_TYPE,
Joiner.on("', '").join(CONTENT_TYPE_MAP.keySet()));
}
private String getContentType(String extension) {
String contentType = CONTENT_TYPE_MAP.get(extension);
return contentType == null ? "" : contentType;
}
@Override
public String getCategory() {
return CommandCategory.INGEST.getName();
}
}