package com.indeed.imhotep.shortlink;
import com.indeed.imhotep.web.KerberosUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.log4j.Logger;
import org.springframework.core.env.PropertyResolver;
import java.io.IOException;
/**
* @author jack@indeed.com (Jack Humphrey)
*/
public class HDFSShortLinkRepository implements ShortLinkRepository {
static final Logger log = Logger.getLogger(HDFSShortLinkRepository.class);
private boolean enabled;
private FileSystem hdfs;
private Path linkPath;
private boolean worldWritable;
public HDFSShortLinkRepository(final PropertyResolver props) {
enabled = true;
try {
kerberosLogin(props);
linkPath = new Path(props.getProperty("shortlink.hdfs.path", String.class));
hdfs = linkPath.getFileSystem(new Configuration());
log.info("Short linking will use HDFS path: " + linkPath);
worldWritable = props.getProperty("shortlink.hdfs.worldwritable", Boolean.class, true);
if(!hdfs.exists(linkPath)) {
hdfs.mkdirs(linkPath);
if(worldWritable) {
hdfs.setPermission(linkPath, FsPermission.valueOf("-rwxrwxrwx"));
}
}
log.info("HDFSShortLinkRepository initialized");
} catch (Exception e) {
log.info("Failed to initialize the HDFS client. Shortlinking disabled.", e);
enabled = false;
}
}
private void kerberosLogin(PropertyResolver props) {
try {
KerberosUtils.loginFromKeytab(props.getProperty("kerberos.principal"), props.getProperty("kerberos.keytab"));
} catch (IOException e) {
log.error("Failed to log in to Kerberos", e);
}
}
@Override
public boolean mapShortCode(String code, String paramString) throws IOException {
if(!enabled) {
throw new IllegalStateException("Shortlink feature disabled");
}
final Path filePath = new Path(linkPath, code);
final Path tempPath = new Path(filePath.toString() + "." + (System.currentTimeMillis() % 100000) + ".tmp");
FSDataOutputStream out = hdfs.create(tempPath);
out.writeUTF(paramString);
out.close();
hdfs.rename(tempPath, filePath);
return true;
}
@Override
public String resolveShortCode(String shortCode) throws IOException {
if(!enabled) {
throw new IllegalStateException("Shortlink feature disabled");
}
Path linkFile = new Path(linkPath, shortCode);
FSDataInputStream in = hdfs.open(linkFile);
final String query = in.readUTF();
in.close();
return query;
}
@Override
public boolean isEnabled() {
return enabled;
}
}