package com.manning.hip.ch3.passwd;
import com.manning.hip.common.HadoopCompat;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.compress.CompressionCodec;
import org.apache.hadoop.io.compress.GzipCodec;
import org.apache.hadoop.mapreduce.RecordWriter;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.ReflectionUtils;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/**
* An {@link org.apache.hadoop.mapreduce.OutputFormat} that writes
* files in /etc/passwd format.
*/
public class PasswdOutputFormat<K, V>
extends FileOutputFormat {
protected static class PasswdRecordWriter<K, V>
extends RecordWriter<K, V> {
private static final String utf8 = "UTF-8";
private static final byte[] newline;
private static final byte[] separator;
static {
try {
newline = "\n".getBytes(utf8);
separator =
PasswdInputFormat.PasswdRecordReader.
PASSWD_LINE_SEPARATOR.getBytes(utf8);
} catch (UnsupportedEncodingException uee) {
throw new IllegalArgumentException("can't find " +
utf8 +
" encoding");
}
}
protected DataOutputStream out;
public PasswdRecordWriter(DataOutputStream out) {
this.out = out;
}
/**
* Write the object to the byte stream, handling Text as a special
* case.
*
* @param o the object to print
* @throws java.io.IOException if the write throws, we pass it on
*/
private void writeObject(Passwd o) throws IOException {
out.write(o.getUsername().getBytes(utf8));
out.write(separator);
out.write(o.getPassword().getBytes(utf8));
out.write(separator);
writeIfNotNull(o.getUid());
out.write(separator);
writeIfNotNull(o.getGid());
out.write(separator);
writeIfNotNull(o.getUidInfo());
out.write(separator);
writeIfNotNull(o.getHomeDir());
out.write(separator);
writeIfNotNull(o.getShell());
}
private void writeIfNotNull(String s)
throws IOException {
if(StringUtils.isNotBlank(s)) {
out.write(s.getBytes(utf8));
}
}
private void writeIfNotNull(Long l)
throws IOException {
if(l != null) {
out.write(l.toString().getBytes(utf8));
}
}
public synchronized void write(K key, V value)
throws IOException {
boolean nullKey = key == null || key instanceof NullWritable;
boolean nullValue = value == null || value instanceof NullWritable;
if (nullKey && nullValue) {
return;
}
if(!nullKey && key instanceof Passwd) {
writeObject((Passwd) key);
out.write(newline);
} else if(!nullValue && value instanceof Passwd) {
writeObject((Passwd) value);
out.write(newline);
}
}
public synchronized void close(TaskAttemptContext context)
throws IOException {
out.close();
}
}
public RecordWriter<K, V>
getRecordWriter(TaskAttemptContext job
) throws IOException, InterruptedException {
Configuration conf = HadoopCompat.getConfiguration(job);
boolean isCompressed = getCompressOutput(job);
CompressionCodec codec = null;
String extension = "";
if (isCompressed) {
Class<? extends CompressionCodec> codecClass =
getOutputCompressorClass(job, GzipCodec.class);
codec = ReflectionUtils.newInstance(codecClass, conf);
extension = codec.getDefaultExtension();
}
Path file = getDefaultWorkFile(job, extension);
FileSystem fs = file.getFileSystem(conf);
if (!isCompressed) {
FSDataOutputStream fileOut = fs.create(file, false);
return new PasswdRecordWriter<K, V>(fileOut);
} else {
FSDataOutputStream fileOut = fs.create(file, false);
return new PasswdRecordWriter<K, V>(new DataOutputStream
(codec.createOutputStream(fileOut)));
}
}
}