/*
Copyright 2011, Lightbox Technologies, 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 com.lightboxtechnologies.spectrum;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import org.apache.commons.io.IOUtils;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketAddress;
public class MRCoffeeClient implements Closeable {
public static class Result {
public final String stdout;
public final String stderr;
public Result(String stdout, String stderr) {
this.stdout = stdout;
this.stderr = stderr;
}
}
protected final Socket sock;
protected DataInputStream in;
protected DataOutputStream out;
protected final StringBuilder stdout_sb = new StringBuilder();
protected final StringBuilder stderr_sb = new StringBuilder();
protected final byte[] buf = new byte[4096];
public MRCoffeeClient() throws IOException {
sock = AFUNIXSocket.newInstance();
}
static {
final String libname = "libjunixsocket-linux-1.5-amd64.so";
final String tmpdir = System.getProperty("java.io.tmpdir");
final String src = '/' + libname;
final File dst = new File(tmpdir + '/' + libname);
if (!dst.exists()) {
try {
extract_lib(src, dst);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
// System.load(dst.toString());
System.setProperty("org.newsclub.net.unix.library.path", tmpdir);
}
protected static void extract_lib(String src, File dst) throws IOException {
InputStream in = null;
try {
in = MRCoffeeJob.class.getResourceAsStream(src);
if (in == null) {
throw new IOException(src + " not found!");
}
OutputStream out = null;
try {
out = new FileOutputStream(dst);
IOUtils.copy(in, out);
out.close();
}
finally {
IOUtils.closeQuietly(out);
}
in.close();
}
finally {
IOUtils.closeQuietly(in);
}
}
public void open(File pipe) throws IOException {
sock.connect(new AFUNIXSocketAddress(pipe));
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
}
public DataOutputStream getOutputStream() {
return out;
}
public void writeCommand(byte[] command) throws IOException {
writeLength(command.length);
writeData(command);
}
public void writeLength(long length) throws IOException {
out.writeLong(length);
}
public void writeData(byte[] data, int offset, int length)
throws IOException {
out.write(data, offset, length);
}
public void writeData(byte[] data) throws IOException {
writeData(data, 0, data.length);
}
public Result readResult() throws IOException {
// reset the buffers
stdout_sb.setLength(0);
stderr_sb.setLength(0);
// read the reply, block by block
boolean out_done = false, err_done = false;
while (!out_done || !err_done) {
// read source file descriptor for this block
final int fd = in.readInt();
// read length of block
long len = in.readLong();
// check whether one of the streams has ended
if (len == 0) {
if (fd == 1) { // stdout
out_done = true;
continue;
}
else if (fd == 2) { // stderr
err_done = true;
continue;
}
}
final StringBuilder sb = fd == 1 ? stdout_sb : stderr_sb;
// read the data block
int size;
for ( ; len > 0; len -= size) {
size = (int) Math.min(buf.length, len);
in.readFully(buf, 0, size);
sb.append(new String(buf, 0, size));
}
}
return new Result(stdout_sb.toString(), stderr_sb.toString());
}
public void close() throws IOException {
boolean hadException = false;
try {
if (in != null) in.close();
if (out != null) out.close();
if (sock != null) sock.close();
}
catch (IOException e) {
hadException = true;
throw (IOException) new IOException().initCause(e);
}
finally {
if (hadException) {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
IOUtils.closeQuietly(sock);
}
}
}
}