
ars.invoke.remote.StandardRemoteChannel Maven / Gradle / Ivy
package ars.invoke.remote;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.ReadableByteChannel;
import java.util.Map;
import java.util.UUID;
import java.util.Locale;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Collection;
import java.util.regex.Pattern;
import ars.util.Nfile;
import ars.util.Jsons;
import ars.util.Streams;
import ars.util.Strings;
import ars.util.AbstractTimerServer;
import ars.invoke.Context;
import ars.invoke.request.Requester;
import ars.invoke.remote.slice.Itoken;
import ars.invoke.remote.slice.Istring;
import ars.invoke.remote.slice.Istream;
import ars.invoke.remote.slice._ResourceDisp;
import ars.invoke.remote.slice.AMD_Resource_invoke;
import ars.invoke.remote.slice.AMD_Resource_upload;
import ars.invoke.remote.slice.AMD_Resource_download;
/**
* 基于ICE消息中间的远程调用通道标准实现
*
* @author wuyongqiang
*/
public class StandardRemoteChannel extends _ResourceDisp implements RemoteChannel {
private static final long serialVersionUID = 1L;
private static final Pattern UPLOAD_FILE_PATTERN = Pattern
.compile("upload-[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}..+");
private transient Context context;
private transient Map streams = new HashMap(0);
/**
* 数据流读取抽象类
*
* 如果数据流超过10秒为被读取则自动关闭并销毁
*
* @author wuyongqiang
*/
abstract class StreamReader {
protected final String id;
protected final AbstractTimerServer timer;
private boolean destroied;
private volatile long timestamp = System.currentTimeMillis();
public StreamReader(String id) {
if (id == null) {
throw new IllegalArgumentException("Id must not be null");
}
this.id = id;
this.timer = new AbstractTimerServer() {
@Override
protected void execute() throws Exception {
if (System.currentTimeMillis() - timestamp > 10000) {
StreamReader.this.destroy();
}
}
};
this.timer.setInterval(1);
this.timer.start();
}
/**
* 读取数据流
*
* @param index 开始位置
* @param length 数据长度
* @return 字节数组
* @throws IOException IO操作异常
*/
public abstract byte[] read(int index, int length) throws IOException;
/**
* 关闭数据流
*
* @throws IOException IO操作异常
*/
public abstract void close() throws IOException;
/**
* 获取数据流并更新时间戳
*
* @param index 开始位置
* @param length 数据长度
* @return 字节数组
* @throws IOException IO操作异常
*/
public byte[] fetch(int index, int length) throws IOException {
this.timestamp = System.currentTimeMillis();
return this.read(index, length);
}
/**
* 销毁流对象
*
* @throws IOException IO操作异常
*/
public void destroy() throws IOException {
if (!this.destroied) {
synchronized (this) {
if (!this.destroied) {
this.destroied = true;
try {
this.close();
} finally {
timer.stop();
streams.remove(id);
}
}
}
}
}
}
/**
* 文件流读取实现
*
* @author wuyongqiang
*/
class FileStreamReader extends StreamReader {
protected final long size;
protected final InputStream stream;
public FileStreamReader(String id, File file) throws IOException {
super(id);
if (file == null) {
throw new IllegalArgumentException("File must not be null");
}
this.size = file.length();
this.stream = new FileInputStream(file);
}
public FileStreamReader(String id, Nfile file) throws IOException {
super(id);
if (file == null) {
throw new IllegalArgumentException("Nfile must not be null");
}
this.size = file.getSize();
this.stream = file.getInputStream();
}
@Override
public byte[] read(int index, int length) throws IOException {
long unread = this.size - index;
boolean end = length >= unread;
byte[] buffer = new byte[end ? (int) unread : length];
try {
this.stream.read(buffer);
return buffer;
} finally {
if (end) {
this.destroy();
}
}
}
@Override
public void close() throws IOException {
this.stream.close();
}
}
/**
* 输入流读取实现
*
* @author wuyongqiang
*/
class InputStreamReader extends StreamReader {
protected final InputStream stream;
public InputStreamReader(String id, InputStream stream) {
super(id);
if (stream == null) {
throw new IllegalArgumentException("InputStream must not be null");
}
this.stream = stream;
}
@Override
public byte[] read(int index, int length) throws IOException {
try {
return Streams.getBytes(this.stream);
} finally {
this.destroy();
}
}
@Override
public void close() throws IOException {
this.stream.close();
}
}
/**
* 字节数组读取实现
*
* @author wuyongqiang
*/
class ByteArrayStreamReader extends StreamReader {
protected final byte[] bytes;
public ByteArrayStreamReader(String id, byte[] bytes) {
super(id);
if (bytes == null) {
throw new IllegalArgumentException("Bytes must not be null");
}
this.bytes = bytes;
}
@Override
public byte[] read(int index, int length) throws IOException {
try {
return this.bytes;
} finally {
this.destroy();
}
}
@Override
public void close() throws IOException {
}
}
/**
* 字节通道读取实现
*
* @author wuyongqiang
*/
class ByteChannelStreamReader extends StreamReader {
protected final ReadableByteChannel channel;
public ByteChannelStreamReader(String id, ReadableByteChannel channel) {
super(id);
if (channel == null) {
throw new IllegalArgumentException("ReadableByteChannel must not be null");
}
this.channel = channel;
}
@Override
public byte[] read(int index, int length) throws IOException {
try {
return Streams.getBytes(this.channel);
} finally {
this.destroy();
}
}
@Override
public void close() throws IOException {
this.channel.close();
}
}
/**
* 根据请求参数JSON字符串获取请求参数键/值映射
*
* @param parameter JSON参数
* @return 参数键/值映射
*/
@SuppressWarnings("unchecked")
protected Map getParameters(String parameter) {
if (Strings.isEmpty(parameter)) {
return new HashMap(0);
}
Map parameters = (Map) Jsons.parse(parameter);
for (Entry entry : parameters.entrySet()) {
Object value = entry.getValue();
if (value instanceof CharSequence && UPLOAD_FILE_PATTERN.matcher((CharSequence) value).matches()) {
String name = ((CharSequence) value).toString();
entry.setValue(new Nfile(name.substring(name.indexOf('.') + 1), new File(Remotes.getDirectory(), name)));
} else if (value instanceof Object[]) {
Object[] array = (Object[]) value;
if (array.length > 0) {
for (int i = 0; i < array.length; i++) {
Object item = array[i];
if (item instanceof CharSequence && UPLOAD_FILE_PATTERN.matcher((CharSequence) item).matches()) {
String name = ((CharSequence) item).toString();
array[i] = new Nfile(name.substring(name.indexOf('.') + 1), new File(
Remotes.getDirectory(), name));
}
}
}
} else if (value instanceof Collection) {
Collection