/**
* 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.blur.command.stream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.Iterator;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.blur.log.Log;
import org.apache.blur.log.LogFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import com.google.common.io.Closer;
public class StreamClient implements Closeable {
private static final Log LOG = LogFactory.getLog(StreamClient.class);
private final String _host;
private final int _port;
private final Socket _socket;
private final DataInputStream _dataInputStream;
private final DataOutputStream _dataOutputStream;
private final Closer _closer = Closer.create();
public StreamClient(String host, int port, int timeout) throws IOException {
_host = host;
_port = port;
_socket = _closer.register(new Socket(_host, _port));
_socket.setTcpNoDelay(true);
_socket.setSoTimeout(timeout);
_dataInputStream = new DataInputStream(_closer.register(_socket.getInputStream()));
_dataOutputStream = new DataOutputStream(_closer.register(_socket.getOutputStream()));
}
public String getHost() {
return _host;
}
public int getPort() {
return _port;
}
public DataInputStream getDataInputStream() {
return _dataInputStream;
}
public DataOutputStream getDataOutStream() {
return _dataOutputStream;
}
@Override
public void close() throws IOException {
_closer.close();
}
public boolean isClassLoaderAvailable(String classLoaderId) throws IOException {
_dataOutputStream.write(StreamCommand.CLASS_LOAD_CHECK.getCommand());
StreamUtil.writeString(_dataOutputStream, classLoaderId);
_dataOutputStream.flush();
String message = StreamUtil.readString(_dataInputStream);
if (message.equals("OK")) {
return true;
} else {
return false;
}
}
public void loadJars(String classLoaderId, Iterable<String> testJars) throws IOException {
_dataOutputStream.write(StreamCommand.CLASS_LOAD.getCommand());
StreamUtil.writeString(_dataOutputStream, classLoaderId);
sendZip(testJars, _dataOutputStream);
_dataOutputStream.flush();
String message = StreamUtil.readString(_dataInputStream);
if (!message.equals("LOADED")) {
throw new IOException("Unknown error during load, check logs on server.");
}
}
private void sendZip(Iterable<String> testJars, DataOutputStream outputStream) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(out);
for (String jar : testJars) {
LOG.info("Sending jar [{0}]", jar);
File file = new File(jar);
FileInputStream in = new FileInputStream(file);
zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
IOUtils.copy(in, zipOutputStream);
in.close();
zipOutputStream.closeEntry();
}
zipOutputStream.close();
byte[] bs = out.toByteArray();
outputStream.writeInt(bs.length);
outputStream.write(bs);
}
public void loadJars(String classLoaderId, String... testJars) throws IOException {
loadJars(classLoaderId, Arrays.asList(testJars));
}
public <T> Iterable<T> executeStream(StreamSplit streamSplit, StreamFunction<T> streamFunction)
throws StreamException {
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
try {
_dataOutputStream.write(StreamCommand.STREAM.getCommand());
byte[] streamSplitBytes = StreamUtil.toBytes(streamSplit.copy());
byte[] streamFunctionBytes = StreamUtil.toBytes(streamFunction);
_dataOutputStream.writeInt(streamSplitBytes.length);
_dataOutputStream.write(streamSplitBytes);
_dataOutputStream.writeInt(streamFunctionBytes.length);
_dataOutputStream.write(streamFunctionBytes);
_dataOutputStream.flush();
ObjectInputStream objectInputStream = new ObjectInputStream(_dataInputStream);
return new Iterator<T>() {
private boolean _more = true;
private Object _obj;
@Override
public boolean hasNext() {
if (!_more) {
return false;
}
if (_obj != null) {
return true;
}
Object o;
try {
o = objectInputStream.readObject();
} catch (ClassNotFoundException | IOException e) {
throw new RuntimeException(e);
}
if (o instanceof StreamComplete) {
return _more = false;
}
_obj = o;
return true;
}
@SuppressWarnings("unchecked")
@Override
public T next() {
T o = (T) _obj;
_obj = null;
if (o instanceof StreamError) {
throw new StreamException(((StreamError) o).getThrowable());
}
return o;
}
};
} catch (IOException e) {
throw new RuntimeException("Unknown error.", e);
}
}
};
}
}