/**
* 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.camel.component.hdfs;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.UriParam;
import org.apache.camel.spi.UriParams;
import org.apache.camel.spi.UriPath;
import org.apache.camel.util.URISupport;
import org.apache.hadoop.io.SequenceFile;
@UriParams
public class HdfsConfiguration {
private URI uri;
private boolean wantAppend;
private List<HdfsProducer.SplitStrategy> splitStrategies;
@UriPath @Metadata(required = "true")
private String hostName;
@UriPath(defaultValue = "" + HdfsConstants.DEFAULT_PORT)
private int port = HdfsConstants.DEFAULT_PORT;
@UriPath @Metadata(required = "true")
private String path;
@UriParam(label = "producer", defaultValue = "true")
private boolean overwrite = true;
@UriParam(label = "producer")
private boolean append;
@UriParam(label = "advanced")
private String splitStrategy;
@UriParam(label = "advanced", defaultValue = "" + HdfsConstants.DEFAULT_BUFFERSIZE)
private int bufferSize = HdfsConstants.DEFAULT_BUFFERSIZE;
@UriParam(label = "advanced", defaultValue = "" + HdfsConstants.DEFAULT_REPLICATION)
private short replication = HdfsConstants.DEFAULT_REPLICATION;
@UriParam(label = "advanced", defaultValue = "" + HdfsConstants.DEFAULT_BLOCKSIZE)
private long blockSize = HdfsConstants.DEFAULT_BLOCKSIZE;
@UriParam(label = "advanced", defaultValue = "NONE")
private SequenceFile.CompressionType compressionType = HdfsConstants.DEFAULT_COMPRESSIONTYPE;
@UriParam(label = "advanced", defaultValue = "DEFAULT")
private HdfsCompressionCodec compressionCodec = HdfsConstants.DEFAULT_CODEC;
@UriParam(defaultValue = "NORMAL_FILE")
private HdfsFileType fileType = HdfsFileType.NORMAL_FILE;
@UriParam(defaultValue = "HDFS")
private HdfsFileSystemType fileSystemType = HdfsFileSystemType.HDFS;
@UriParam(defaultValue = "NULL")
private WritableType keyType = WritableType.NULL;
@UriParam(defaultValue = "BYTES")
private WritableType valueType = WritableType.BYTES;
@UriParam(label = "advanced", defaultValue = HdfsConstants.DEFAULT_OPENED_SUFFIX)
private String openedSuffix = HdfsConstants.DEFAULT_OPENED_SUFFIX;
@UriParam(label = "advanced", defaultValue = HdfsConstants.DEFAULT_READ_SUFFIX)
private String readSuffix = HdfsConstants.DEFAULT_READ_SUFFIX;
@UriParam(label = "consumer")
private long initialDelay;
@UriParam(label = "consumer", defaultValue = "" + HdfsConstants.DEFAULT_DELAY)
private long delay = HdfsConstants.DEFAULT_DELAY;
@UriParam(label = "consumer", defaultValue = HdfsConstants.DEFAULT_PATTERN)
private String pattern = HdfsConstants.DEFAULT_PATTERN;
@UriParam(label = "advanced", defaultValue = "" + HdfsConstants.DEFAULT_BUFFERSIZE)
private int chunkSize = HdfsConstants.DEFAULT_BUFFERSIZE;
@UriParam(label = "advanced", defaultValue = "" + HdfsConstants.DEFAULT_CHECK_IDLE_INTERVAL)
private int checkIdleInterval = HdfsConstants.DEFAULT_CHECK_IDLE_INTERVAL;
@UriParam(defaultValue = "true")
private boolean connectOnStartup = true;
@UriParam
private String owner;
public HdfsConfiguration() {
}
private Boolean getBoolean(Map<String, Object> hdfsSettings, String param, Boolean dflt) {
if (hdfsSettings.containsKey(param)) {
return Boolean.valueOf((String) hdfsSettings.get(param));
} else {
return dflt;
}
}
private Integer getInteger(Map<String, Object> hdfsSettings, String param, Integer dflt) {
if (hdfsSettings.containsKey(param)) {
return Integer.valueOf((String) hdfsSettings.get(param));
} else {
return dflt;
}
}
private Short getShort(Map<String, Object> hdfsSettings, String param, Short dflt) {
if (hdfsSettings.containsKey(param)) {
return Short.valueOf((String) hdfsSettings.get(param));
} else {
return dflt;
}
}
private Long getLong(Map<String, Object> hdfsSettings, String param, Long dflt) {
if (hdfsSettings.containsKey(param)) {
return Long.valueOf((String) hdfsSettings.get(param));
} else {
return dflt;
}
}
private HdfsFileType getFileType(Map<String, Object> hdfsSettings, String param, HdfsFileType dflt) {
String eit = (String) hdfsSettings.get(param);
if (eit != null) {
return HdfsFileType.valueOf(eit);
} else {
return dflt;
}
}
private HdfsFileSystemType getFileSystemType(Map<String, Object> hdfsSettings, String param, HdfsFileSystemType dflt) {
String eit = (String) hdfsSettings.get(param);
if (eit != null) {
return HdfsFileSystemType.valueOf(eit);
} else {
return dflt;
}
}
private WritableType getWritableType(Map<String, Object> hdfsSettings, String param, WritableType dflt) {
String eit = (String) hdfsSettings.get(param);
if (eit != null) {
return WritableType.valueOf(eit);
} else {
return dflt;
}
}
private SequenceFile.CompressionType getCompressionType(Map<String, Object> hdfsSettings, String param, SequenceFile.CompressionType ct) {
String eit = (String) hdfsSettings.get(param);
if (eit != null) {
return SequenceFile.CompressionType.valueOf(eit);
} else {
return ct;
}
}
private HdfsCompressionCodec getCompressionCodec(Map<String, Object> hdfsSettings, String param, HdfsCompressionCodec cd) {
String eit = (String) hdfsSettings.get(param);
if (eit != null) {
return HdfsCompressionCodec.valueOf(eit);
} else {
return cd;
}
}
private String getString(Map<String, Object> hdfsSettings, String param, String dflt) {
if (hdfsSettings.containsKey(param)) {
return (String) hdfsSettings.get(param);
} else {
return dflt;
}
}
private List<HdfsProducer.SplitStrategy> getSplitStrategies(Map<String, Object> hdfsSettings) {
List<HdfsProducer.SplitStrategy> strategies = new ArrayList<HdfsProducer.SplitStrategy>();
for (Object obj : hdfsSettings.keySet()) {
String key = (String) obj;
if ("splitStrategy".equals(key)) {
String eit = (String) hdfsSettings.get(key);
if (eit != null) {
String[] strstrategies = eit.split(",");
for (String strstrategy : strstrategies) {
String tokens[] = strstrategy.split(":");
if (tokens.length != 2) {
throw new IllegalArgumentException("Wrong Split Strategy " + key + "=" + eit);
}
HdfsProducer.SplitStrategyType sst = HdfsProducer.SplitStrategyType.valueOf(tokens[0]);
long ssv = Long.valueOf(tokens[1]);
strategies.add(new HdfsProducer.SplitStrategy(sst, ssv));
}
}
}
}
return strategies;
}
public void checkConsumerOptions() {
}
public void checkProducerOptions() {
if (isAppend()) {
if (getSplitStrategies().size() != 0) {
throw new IllegalArgumentException("Split Strategies incompatible with append=true");
}
if (getFileType() != HdfsFileType.NORMAL_FILE) {
throw new IllegalArgumentException("append=true works only with NORMAL_FILEs");
}
}
}
public void parseURI(URI uri) throws URISyntaxException {
String protocol = uri.getScheme();
if (!protocol.equalsIgnoreCase("hdfs")) {
throw new IllegalArgumentException("Unrecognized protocol: " + protocol + " for uri: " + uri);
}
hostName = uri.getHost();
if (hostName == null) {
hostName = "localhost";
}
port = uri.getPort() == -1 ? HdfsConstants.DEFAULT_PORT : uri.getPort();
path = uri.getPath();
Map<String, Object> hdfsSettings = URISupport.parseParameters(uri);
overwrite = getBoolean(hdfsSettings, "overwrite", overwrite);
append = getBoolean(hdfsSettings, "append", append);
wantAppend = append;
bufferSize = getInteger(hdfsSettings, "bufferSize", bufferSize);
replication = getShort(hdfsSettings, "replication", replication);
blockSize = getLong(hdfsSettings, "blockSize", blockSize);
compressionType = getCompressionType(hdfsSettings, "compressionType", compressionType);
compressionCodec = getCompressionCodec(hdfsSettings, "compressionCodec", compressionCodec);
fileType = getFileType(hdfsSettings, "fileType", fileType);
fileSystemType = getFileSystemType(hdfsSettings, "fileSystemType", fileSystemType);
keyType = getWritableType(hdfsSettings, "keyType", keyType);
valueType = getWritableType(hdfsSettings, "valueType", valueType);
openedSuffix = getString(hdfsSettings, "openedSuffix", openedSuffix);
readSuffix = getString(hdfsSettings, "readSuffix", readSuffix);
initialDelay = getLong(hdfsSettings, "initialDelay", initialDelay);
delay = getLong(hdfsSettings, "delay", delay);
pattern = getString(hdfsSettings, "pattern", pattern);
chunkSize = getInteger(hdfsSettings, "chunkSize", chunkSize);
splitStrategies = getSplitStrategies(hdfsSettings);
}
public URI getUri() {
return uri;
}
public void setUri(URI uri) {
this.uri = uri;
}
public String getHostName() {
return hostName;
}
/**
* HDFS host to use
*/
public void setHostName(String hostName) {
this.hostName = hostName;
}
public int getPort() {
return port;
}
/**
* HDFS port to use
*/
public void setPort(int port) {
this.port = port;
}
public String getPath() {
return path;
}
/**
* The directory path to use
*/
public void setPath(String path) {
this.path = path;
}
public boolean isOverwrite() {
return overwrite;
}
/**
* Whether to overwrite existing files with the same name
*/
public void setOverwrite(boolean overwrite) {
this.overwrite = overwrite;
}
public boolean isAppend() {
return append;
}
public boolean isWantAppend() {
return wantAppend;
}
/**
* Append to existing file. Notice that not all HDFS file systems support the append option.
*/
public void setAppend(boolean append) {
this.append = append;
}
public int getBufferSize() {
return bufferSize;
}
/**
* The buffer size used by HDFS
*/
public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
}
public short getReplication() {
return replication;
}
/**
* The HDFS replication factor
*/
public void setReplication(short replication) {
this.replication = replication;
}
public long getBlockSize() {
return blockSize;
}
/**
* The size of the HDFS blocks
*/
public void setBlockSize(long blockSize) {
this.blockSize = blockSize;
}
public HdfsFileType getFileType() {
return fileType;
}
/**
* The file type to use. For more details see Hadoop HDFS documentation about the various files types.
*/
public void setFileType(HdfsFileType fileType) {
this.fileType = fileType;
}
public SequenceFile.CompressionType getCompressionType() {
return compressionType;
}
/**
* The compression type to use (is default not in use)
*/
public void setCompressionType(SequenceFile.CompressionType compressionType) {
this.compressionType = compressionType;
}
public HdfsCompressionCodec getCompressionCodec() {
return compressionCodec;
}
/**
* The compression codec to use
*/
public void setCompressionCodec(HdfsCompressionCodec compressionCodec) {
this.compressionCodec = compressionCodec;
}
/**
* Set to LOCAL to not use HDFS but local java.io.File instead.
*/
public void setFileSystemType(HdfsFileSystemType fileSystemType) {
this.fileSystemType = fileSystemType;
}
public HdfsFileSystemType getFileSystemType() {
return fileSystemType;
}
public WritableType getKeyType() {
return keyType;
}
/**
* The type for the key in case of sequence or map files.
*/
public void setKeyType(WritableType keyType) {
this.keyType = keyType;
}
public WritableType getValueType() {
return valueType;
}
/**
* The type for the key in case of sequence or map files
*/
public void setValueType(WritableType valueType) {
this.valueType = valueType;
}
/**
* When a file is opened for reading/writing the file is renamed with this suffix to avoid to read it during the writing phase.
*/
public void setOpenedSuffix(String openedSuffix) {
this.openedSuffix = openedSuffix;
}
public String getOpenedSuffix() {
return openedSuffix;
}
/**
* Once the file has been read is renamed with this suffix to avoid to read it again.
*/
public void setReadSuffix(String readSuffix) {
this.readSuffix = readSuffix;
}
public String getReadSuffix() {
return readSuffix;
}
/**
* For the consumer, how much to wait (milliseconds) before to start scanning the directory.
*/
public void setInitialDelay(long initialDelay) {
this.initialDelay = initialDelay;
}
public long getInitialDelay() {
return initialDelay;
}
/**
* The interval (milliseconds) between the directory scans.
*/
public void setDelay(long delay) {
this.delay = delay;
}
public long getDelay() {
return delay;
}
/**
* The pattern used for scanning the directory
*/
public void setPattern(String pattern) {
this.pattern = pattern;
}
public String getPattern() {
return pattern;
}
/**
* When reading a normal file, this is split into chunks producing a message per chunk.
*/
public void setChunkSize(int chunkSize) {
this.chunkSize = chunkSize;
}
public int getChunkSize() {
return chunkSize;
}
/**
* How often (time in millis) in to run the idle checker background task. This option is only in use if the splitter strategy is IDLE.
*/
public void setCheckIdleInterval(int checkIdleInterval) {
this.checkIdleInterval = checkIdleInterval;
}
public int getCheckIdleInterval() {
return checkIdleInterval;
}
public List<HdfsProducer.SplitStrategy> getSplitStrategies() {
return splitStrategies;
}
public String getSplitStrategy() {
return splitStrategy;
}
/**
* In the current version of Hadoop opening a file in append mode is disabled since it's not very reliable. So, for the moment,
* it's only possible to create new files. The Camel HDFS endpoint tries to solve this problem in this way:
* <ul>
* <li>If the split strategy option has been defined, the hdfs path will be used as a directory and files will be created using the configured UuidGenerator.</li>
* <li>Every time a splitting condition is met, a new file is created.</li>
* </ul>
* The splitStrategy option is defined as a string with the following syntax:
* <br/><tt>splitStrategy=ST:value,ST:value,...</tt>
* <br/>where ST can be:
* <ul>
* <li>BYTES a new file is created, and the old is closed when the number of written bytes is more than value</li>
* <li>MESSAGES a new file is created, and the old is closed when the number of written messages is more than value</li>
* <li>IDLE a new file is created, and the old is closed when no writing happened in the last value milliseconds</li>
* </ul>
*/
public void setSplitStrategy(String splitStrategy) {
this.splitStrategy = splitStrategy;
}
public boolean isConnectOnStartup() {
return connectOnStartup;
}
/**
* Whether to connect to the HDFS file system on starting the producer/consumer.
* If false then the connection is created on-demand. Notice that HDFS may take up till 15 minutes to establish
* a connection, as it has hardcoded 45 x 20 sec redelivery. By setting this option to false allows your
* application to startup, and not block for up till 15 minutes.
*/
public void setConnectOnStartup(boolean connectOnStartup) {
this.connectOnStartup = connectOnStartup;
}
public String getOwner() {
return owner;
}
/**
* The file owner must match this owner for the consumer to pickup the file. Otherwise the file is skipped.
*/
public void setOwner(String owner) {
this.owner = owner;
}
}