use of io.netty.util.concurrent.GenericFutureListener in project jersey by eclipse-ee4j.
the class NettyConnector method execute.
protected CompletableFuture<ClientResponse> execute(final ClientRequest jerseyRequest) {
Integer timeout = jerseyRequest.resolveProperty(ClientProperties.READ_TIMEOUT, 0);
if (timeout == null || timeout < 0) {
throw new ProcessingException(LocalizationMessages.WRONG_READ_TIMEOUT(timeout));
}
final CompletableFuture<ClientResponse> responseAvailable = new CompletableFuture<>();
final CompletableFuture<?> responseDone = new CompletableFuture<>();
final URI requestUri = jerseyRequest.getUri();
String host = requestUri.getHost();
int port = requestUri.getPort() != -1 ? requestUri.getPort() : "https".equals(requestUri.getScheme()) ? 443 : 80;
try {
String key = requestUri.getScheme() + "://" + host + ":" + port;
ArrayList<Channel> conns;
synchronized (connections) {
conns = connections.get(key);
if (conns == null) {
conns = new ArrayList<>(0);
connections.put(key, conns);
}
}
Channel chan = null;
synchronized (conns) {
while (chan == null && !conns.isEmpty()) {
chan = conns.remove(conns.size() - 1);
try {
chan.pipeline().remove(INACTIVE_POOLED_CONNECTION_HANDLER);
chan.pipeline().remove(PRUNE_INACTIVE_POOL);
} catch (NoSuchElementException e) {
/*
* Eat it.
* It could happen that the channel was closed, pipeline cleared and
* then it will fail to remove the names with this exception.
*/
}
if (!chan.isOpen()) {
chan = null;
}
}
}
if (chan == null) {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
// Enable HTTPS if necessary.
if ("https".equals(requestUri.getScheme())) {
// making client authentication optional for now; it could be extracted to configurable property
JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE);
p.addLast(jdkSslContext.newHandler(ch.alloc()));
}
// http proxy
Configuration config = jerseyRequest.getConfiguration();
final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
if (proxyUri != null) {
final URI u = getProxyUri(proxyUri);
final String userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
final String password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
p.addLast(new HttpProxyHandler(new InetSocketAddress(u.getHost(), u.getPort() == -1 ? 8080 : u.getPort()), userName, password));
}
p.addLast(new HttpClientCodec());
p.addLast(new ChunkedWriteHandler());
p.addLast(new HttpContentDecompressor());
}
});
// connect timeout
Integer connectTimeout = jerseyRequest.resolveProperty(ClientProperties.CONNECT_TIMEOUT, 0);
if (connectTimeout > 0) {
b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
}
// Make the connection attempt.
chan = b.connect(host, port).sync().channel();
}
// assert: clientHandler will always notify responseDone: either normally, or exceptionally
// assert: clientHandler may notify responseAvailable, if sufficient parts of response are detected to construct
// a valid ClientResponse
// assert: responseAvailable completion may be racing against responseDone completion
// assert: it is ok to abort the entire response, if responseDone is completed exceptionally - in particular, nothing
// will leak
final Channel ch = chan;
JerseyClientHandler clientHandler = new JerseyClientHandler(jerseyRequest, responseAvailable, responseDone);
// read timeout makes sense really as an inactivity timeout
ch.pipeline().addLast(READ_TIMEOUT_HANDLER, new IdleStateHandler(0, 0, timeout, TimeUnit.MILLISECONDS));
ch.pipeline().addLast(REQUEST_HANDLER, clientHandler);
responseDone.whenComplete((_r, th) -> {
ch.pipeline().remove(READ_TIMEOUT_HANDLER);
ch.pipeline().remove(clientHandler);
if (th == null) {
ch.pipeline().addLast(INACTIVE_POOLED_CONNECTION_HANDLER, new IdleStateHandler(0, 0, maxPoolIdle));
ch.pipeline().addLast(PRUNE_INACTIVE_POOL, new PruneIdlePool(connections, key));
boolean added = true;
synchronized (connections) {
ArrayList<Channel> conns1 = connections.get(key);
if (conns1 == null) {
conns1 = new ArrayList<>(1);
conns1.add(ch);
connections.put(key, conns1);
} else {
synchronized (conns1) {
if ((maxPoolSizeTotal == 0 || connections.size() < maxPoolSizeTotal) && conns1.size() < maxPoolSize) {
conns1.add(ch);
} else {
// else do not add the Channel to the idle pool
added = false;
}
}
}
}
if (!added) {
ch.close();
}
} else {
ch.close();
// if responseAvailable has been completed, no-op: jersey will encounter IOException while reading response body
// if responseAvailable has not been completed, abort
responseAvailable.completeExceptionally(th);
}
});
HttpRequest nettyRequest;
String pathWithQuery = buildPathWithQueryParameters(requestUri);
if (jerseyRequest.hasEntity()) {
nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), pathWithQuery);
} else {
nettyRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), pathWithQuery);
}
// headers
for (final Map.Entry<String, List<String>> e : jerseyRequest.getStringHeaders().entrySet()) {
nettyRequest.headers().add(e.getKey(), e.getValue());
}
// host header - http 1.1
nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
if (jerseyRequest.hasEntity()) {
// guard against prematurely closed channel
final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> closeListener = new GenericFutureListener<io.netty.util.concurrent.Future<? super Void>>() {
@Override
public void operationComplete(io.netty.util.concurrent.Future<? super Void> future) throws Exception {
if (!responseDone.isDone()) {
responseDone.completeExceptionally(new IOException("Channel closed."));
}
}
};
ch.closeFuture().addListener(closeListener);
if (jerseyRequest.getLengthLong() == -1) {
HttpUtil.setTransferEncodingChunked(nettyRequest, true);
} else {
nettyRequest.headers().add(HttpHeaderNames.CONTENT_LENGTH, jerseyRequest.getLengthLong());
}
// Send the HTTP request.
ch.writeAndFlush(nettyRequest);
final JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(ch);
jerseyRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() {
@Override
public OutputStream getOutputStream(int contentLength) throws IOException {
return jerseyChunkedInput;
}
});
if (HttpUtil.isTransferEncodingChunked(nettyRequest)) {
ch.write(new HttpChunkedInput(jerseyChunkedInput));
} else {
ch.write(jerseyChunkedInput);
}
executorService.execute(new Runnable() {
@Override
public void run() {
// close listener is not needed any more.
ch.closeFuture().removeListener(closeListener);
try {
jerseyRequest.writeEntity();
} catch (IOException e) {
responseDone.completeExceptionally(e);
}
}
});
ch.flush();
} else {
// Send the HTTP request.
ch.writeAndFlush(nettyRequest);
}
} catch (InterruptedException e) {
responseDone.completeExceptionally(e);
}
return responseAvailable;
}
use of io.netty.util.concurrent.GenericFutureListener in project SMSGate by Lihuanghe.
the class SessionConnectedHandler method userEventTriggered.
@Override
public void userEventTriggered(final ChannelHandlerContext ctx, Object evt) throws Exception {
final AtomicInteger tmptotal = totleCnt;
if (evt == SessionState.Connect) {
final Channel ch = ctx.channel();
EventLoopGroupFactory.INS.submitUnlimitCircleTask(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
int cnt = RandomUtils.nextInt() & 0x4fff;
Promise<BaseMessage> frefuture = null;
while (cnt > 0 && tmptotal.get() > 0) {
List<Promise<BaseMessage>> futures = null;
ChannelFuture chfuture = null;
BaseMessage msg = createTestReq(UUID.randomUUID().toString());
// chfuture = ChannelUtil.asyncWriteToEntity(getEndpointEntity().getId(), msg);
futures = ChannelUtil.syncWriteLongMsgToEntity(getEndpointEntity().getId(), msg);
if (chfuture != null)
chfuture.sync();
cnt--;
tmptotal.decrementAndGet();
if (futures != null) {
try {
for (Promise<BaseMessage> future : futures) {
future.addListener(new GenericFutureListener<Future<BaseMessage>>() {
@Override
public void operationComplete(Future<BaseMessage> future) throws Exception {
if (future.isSuccess()) {
// logger.info("response:{}",future.get());
} else {
// logger.error("response:{}",future.cause());
}
}
});
frefuture = future;
}
} catch (Exception e) {
e.printStackTrace();
cnt--;
tmptotal.decrementAndGet();
break;
}
} else {
// 连接不可写了,等待上一个response回来
// 再把消息发出去
ctx.writeAndFlush(msg);
if (frefuture != null) {
frefuture.sync();
frefuture = null;
} else {
break;
}
}
}
return true;
}
}, new ExitUnlimitCirclePolicy<Boolean>() {
@Override
public boolean notOver(Future<Boolean> future) {
if (future.cause() != null)
future.cause().printStackTrace();
boolean over = ch.isActive() && tmptotal.get() > 0;
if (!over) {
logger.info("========send over.============");
// ch.writeAndFlush(new CmppTerminateRequestMessage());
}
return over;
}
}, 1);
}
ctx.fireUserEventTriggered(evt);
}
use of io.netty.util.concurrent.GenericFutureListener in project SMSGate by Lihuanghe.
the class SessionLoginManager method failedLogin.
@Override
protected /**
* 状态 0:正确 1:消息结构错 2:非法源地址 3:认证错 4:版本太高 5~ :其他错误
*/
void failedLogin(ChannelHandlerContext ctx, Object msg, long status) {
if (msg instanceof CmppConnectRequestMessage) {
logger.error("Connected error status :{},msg : {}", status, msg);
CmppConnectRequestMessage message = (CmppConnectRequestMessage) msg;
// 认证失败
CmppConnectResponseMessage resp = new CmppConnectResponseMessage(message.getHeader().getSequenceId());
resp.setAuthenticatorISMG(new byte[16]);
resp.setStatus(status);
ChannelFuture promise = ctx.writeAndFlush(resp);
final ChannelHandlerContext finalctx = ctx;
promise.addListener(new GenericFutureListener() {
public void operationComplete(Future future) throws Exception {
finalctx.close();
}
});
} else {
logger.error("connect msg type error : {}", msg);
ctx.close();
}
}
use of io.netty.util.concurrent.GenericFutureListener in project SMSGate by Lihuanghe.
the class SgipSessionLoginManager method failedLogin.
@Override
protected void failedLogin(ChannelHandlerContext ctx, Object msg, long status) {
if (msg instanceof SgipBindRequestMessage) {
logger.error("Connected error status :{},msg : {}", status, msg);
SgipBindRequestMessage message = (SgipBindRequestMessage) msg;
// 认证失败
SgipBindResponseMessage resp = new SgipBindResponseMessage(((Message) message).getHeader());
resp.setResult((short) status);
resp.setTimestamp(((Message) message).getTimestamp());
ChannelFuture promise = ctx.writeAndFlush(resp);
final ChannelHandlerContext finalctx = ctx;
promise.addListener(new GenericFutureListener() {
public void operationComplete(Future future) throws Exception {
finalctx.close();
}
});
} else {
logger.error("connect msg type error : {}", msg);
ctx.close();
}
}
use of io.netty.util.concurrent.GenericFutureListener in project SMSGate by Lihuanghe.
the class SMGPSessionLoginManager method failedLogin.
@Override
protected void failedLogin(ChannelHandlerContext ctx, Object msg, long status) {
if (msg instanceof SMGPLoginMessage) {
logger.error("Connected error status :{},msg : {}", status, msg);
SMGPLoginMessage message = (SMGPLoginMessage) msg;
// 认证失败
SMGPLoginRespMessage resp = new SMGPLoginRespMessage();
resp.setSequenceNo(message.getSequenceNo());
resp.setStatus((int) status);
ChannelFuture promise = ctx.writeAndFlush(resp);
final ChannelHandlerContext finalctx = ctx;
promise.addListener(new GenericFutureListener() {
public void operationComplete(Future future) throws Exception {
finalctx.close();
}
});
} else {
logger.error("connect msg type error : {}", msg);
ctx.close();
}
}
Aggregations