nested exception is io.lettuce.core.RedisCommandExecutionException: ERR no such key - spring-boot

I am using this code to set value in redis(Java 8 + Spring Boot 2.1.12.RELEASE):
public List<App> getApps(App app) {
String key = "app:list:" + app.getAppMark();
String lockKey = "lock:" + key;
List<App> apps = redisTemplate.opsForList().range(key, 0, -1);
if (CollectionUtils.isNotEmpty(apps)) {
return apps;
}
try {
ELocker.lock(lockKey, BizGlobalConstant.DISTRIBUTE_LOCK_DEFAULT_EXPIRE_SECOND);
apps = getDBApps(app);
if (CollectionUtils.isNotEmpty(apps)) {
redisTemplate.opsForList().set(key, 0, apps);
}
} catch (Exception e) {
throw new ServiceException(e.getMessage());
} finally {
ELocker.unLock(lockKey);
}
return apps;
}
when execute to redisTemplate.opsForList().set throw this error:
Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR no such key
what should I do to fix this problem?

tweak code like this:
#Autowired
private RedisTemplate redisTemplate;
private ValueOperations<String, List<App>> listValueOperations;
#PostConstruct
public void before() {
listValueOperations = redisTemplate.opsForValue();
}
#Override
#UseSlave
public List<App> getApps(App app) {
String key = "app:list:" + app.getAppMark();
String lockKey = "lock:" + key;
List<App> apps = listValueOperations.get(key);
if (CollectionUtils.isNotEmpty(apps)) {
return apps;
}
try {
ELocker.lock(lockKey, BizGlobalConstant.DISTRIBUTE_LOCK_DEFAULT_EXPIRE_SECOND);
apps = getDBApps(app);
if (CollectionUtils.isNotEmpty(apps)) {
listValueOperations.set(key, apps);
}
} catch (Exception e) {
throw new ServiceException(e.getMessage());
} finally {
ELocker.unLock(lockKey);
}
return apps;
}

Related

How to get list of objects using Mono ResponseEntity objects, as it returns single object

#RequestMapping("/api/v1")
public class RemoteActionHistoryController {
public Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>> excaliburData(#PathVariable(name = "deviceId", required = true)
String deviceId) {
return service.getRemoteActionHistory(deviceId);
}
}
public class RemoteActionHistoryServiceImpl {
#Autowired
RemoteActionHistoryRepository arrowFlightRepository;
#Override
public Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>> getRemoteActionHistory(String deviceId) throws Exception {
return (Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>>) arrowFlightRepository.getRemoteActionDetailsByDeviceId(deviceId).collectList().flatMap(mapper);
}
Function<List<RemoteActionHistory>, Mono<ResponseEntityDTO<RemoteActionHistoryDTO>>> mapper = remoteActions -> {
var remoteActionDTO = new RemoteActionHistoryDTO();
if (CollectionUtils.isEmpty(remoteActions)) {
return Mono.justOrEmpty(new ResponseEntityDTO<>(RemoteActionHistoryConstants.CODE_RET_000, null, remoteActionDTO));
}
System.out.println("Printing remoteActions"+remoteActions);
for (RemoteActionHistory excaliburData : remoteActions) {
remoteActionDTO.setStartDateTime(excaliburData.getStartDateTime());
remoteActionDTO.setEndDateTime(excaliburData.getEndDateTime());
remoteActionDTO.setRemoteActionType(excaliburData.getCommand());
remoteActionDTO.setTaskStatus(excaliburData.getStatus());
}
return Mono.justOrEmpty(new ResponseEntityDTO<>(RemoteActionHistoryConstants.CODE_RET_000, null, remoteActionDTO));
};
}
public class RemoteActionHistoryServiceImpl {
#Autowired
RemoteActionHistoryRepository arrowFlightRepository;
#Override
public Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>> getRemoteActionHistory(String deviceId) throws Exception {
return (Mono<ResponseEntityDTO<List<RemoteActionHistoryDTO>>>) arrowFlightRepository.getRemoteActionDetailsByDeviceId(deviceId).collectList().flatMap(mapper);
}
Function<List<RemoteActionHistory>, Mono<ResponseEntityDTO<RemoteActionHistoryDTO>>> mapper = remoteActions -> {
var remoteActionDTO = new RemoteActionHistoryDTO();
if (CollectionUtils.isEmpty(remoteActions)) {
return Mono.justOrEmpty(new ResponseEntityDTO<>(RemoteActionHistoryConstants.CODE_RET_000, null, remoteActionDTO));
}
System.out.println("Printing remoteActions"+remoteActions);
for (RemoteActionHistory excaliburData : remoteActions) {
remoteActionDTO.setStartDateTime(excaliburData.getStartDateTime());
remoteActionDTO.setEndDateTime(excaliburData.getEndDateTime());
remoteActionDTO.setRemoteActionType(excaliburData.getCommand());
remoteActionDTO.setTaskStatus(excaliburData.getStatus());
}
return Mono.justOrEmpty(new ResponseEntityDTO<>(RemoteActionHistoryConstants.CODE_RET_000, null, remoteActionDTO));
};
}
public class RemoteActionHistoryRepositoryImpl {
#Override
public Flux<RemoteActionHistory> getRemoteActionDetailsByDeviceId(String deviceId) throws Exception {
return Flux.fromIterable(getExcaliburData(String.format(query, tableName, deviceId), true));
}
private List<RemoteActionHistory> getExcaliburData(String query, boolean retry) throws Exception {
List<RemoteActionHistory> remoteActionData = new ArrayList<>();
try (final FlightStream flightStream = adhocFlightClientConfig.createAdhocFlightClient().runQuery(query);) {
while (flightStream.next()) {
if (!flightStream.hasRoot()) {
break;
}
VectorSchemaRoot vectorSchemaRoot = flightStream.getRoot();
TimeStampMilliVector createdDateVector = (TimeStampMilliVector) vectorSchemaRoot
.getVector(RemoteActionHistoryConstants.CREATED_DATE_TIME);
TimeStampMilliVector modifiedDateVector = (TimeStampMilliVector) vectorSchemaRoot
.getVector(RemoteActionHistoryConstants.MODIFIED_DATE_TIME);
RemoteActionHistory remoteAction = null;
for (int i = 0; i < vectorSchemaRoot.getRowCount(); i++) {
remoteAction = new RemoteActionHistory();
remoteAction.setStartDateTime(createdDateVector.isNull(i)? null : new Timestamp(createdDateVector.get(i)));
remoteAction.setEndDateTime(modifiedDateVector.isNull(i)? null : new Timestamp(modifiedDateVector.get(i)));
remoteActionData.add(remoteAction);
}
} catch (Exception ex) {
log.error(String.format("Exception string : %s with retryEnabled is %s", ex.toString(),retry));
if (retry && StringUtils.containsIgnoreCase(ex.toString(), RemoteActionHistoryConstants.UNAUTHENTICATED_ERROR)) {
adhocFlightClientConfig.removeToken();
getExcaliburData(query, false);
}
throw ex;
}
return remoteActionData;
}
}
I have attached the result which I'm currently getting single record. when i debugged the code in the object i have multiple records but it shows only one record in postman

Hibernate mapping: Get collection on runtime with nullSafeGet overrided method

To make the mapping between hibernate and my database work, I have this mapping :
<property name="userRolesV2" column="user_roles_v2">
<type name="io.markethero.repository.CommaSeparatedGenericEnumType">
<param name="enumClassName">io.markethero.model.UserLoginRoleV2</param>
<param name="collectionClassName">java.util.Set</param>
</type>
</property>
The idea is to directly get the Collection in my field class instead of doing the mapping each time.
For example, the field in the class could be a Set, a List, or a Queue.
In the database, the value is like "enumValue1,enumValue2,enumValue3".
To do that, my class CommaSeparatedGenericEnumType is like this:
public class CommaSeparatedGenericEnumType implements UserType, ParameterizedType {
private Class enumClass = null;
private Class targetCollection = null;
public void setParameterValues(Properties params) {
String enumClassName = params.getProperty("enumClassName");
String collectionClassName = params.getProperty("collectionClassName");
if (enumClassName == null) {
throw new MappingException("enumClassName parameter not specified");
}
if (collectionClassName == null) {
throw new MappingException("collectionClassName parameter not specified");
}
try {
this.enumClass = Class.forName(enumClassName);
} catch (ClassNotFoundException e) {
throw new MappingException("enumClass " + enumClassName + " not found", e);
}
try {
this.targetCollection = Class.forName(collectionClassName);
} catch (ClassNotFoundException e) {
throw new MappingException("targetCollection " + collectionClassName + " not found", e);
}
}
#Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
String commaSeparatedValues = rs.getString(names[0]);
List<Object> result = new ArrayList<>();
if (!rs.wasNull()) {
String[] enums = commaSeparatedValues.split(",");
for (String string : enums) {
result.add(Enum.valueOf(enumClass, string));
}
}
return result;
}
#Override
#SuppressWarnings("unchecked")
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
if (null == value) {
st.setNull(index, Types.VARCHAR);
} else {
List<Object> enums = (List) value;
StringBuilder sb = new StringBuilder("");
for (Object each : enums) {
sb.append(each.toString()).append(",");
}
if (sb.toString().isEmpty()) {
st.setNull(index, Types.VARCHAR);
} else {
String commaSeparatedIds = sb.toString().substring(0, sb.toString().length() - 1);
st.setString(index, commaSeparatedIds);
}
}
}
}
I would like to be able to parametrize which collection nullSafeGet and nullSafeSet are going to use, because for now, it's only working with a list.
Thank you!
Maybe my question was asked was oddly, but here what I did:
For the getter, I used the factory pattern already implemented by Spring : CollectionFactory.
#Override
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
String commaSeparatedValues = rs.getString(names[0]);
Collection<Object> result = CollectionFactory.createCollection(this.targetCollection, 50);
if (!rs.wasNull()) {
String[] enums = commaSeparatedValues.split(",");
for (String string : enums) {
try {
result.add(Enum.valueOf(enumClass, string));
} catch (IllegalArgumentException e) {
throw new MappingException("[CommaSeparatedGenericEnumType::nullSafeGet] No such enum value"+ string +"for enum : " + enumClass, e);
}
}
}
return result;
}
For the setter, I used the reflection API.
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.VARCHAR);
} else {
if (value instanceof Collection) {
try {
StringBuilder sb = new StringBuilder("");
Constructor<?> c = value.getClass().getConstructor(Collection.class);
Collection<Object> enums = (Collection<Object>) c.newInstance((Collection<Object>) value);
for (Object each : enums) {
sb.append(each.toString()).append(",");
}
String commaSeparatedIds = sb.substring(0, sb.toString().length() - 1);
if (sb.length() > 0) {
st.setString(index, commaSeparatedIds);
} else {
st.setNull(index, Types.VARCHAR);
}
} catch (NoSuchMethodException e) {
throw new MappingException("[CommaSeparatedGenericEnumType::nullSafeSet] No such constructor found for class : " + value.getClass(), e);
} catch (InstantiationException e) {
throw new MappingException("[CommaSeparatedGenericEnumType::nullSafeSet] Class : " + value.getClass() + " cannot be instantiate ", e);
} catch (IllegalAccessException e) {
throw new MappingException("[CommaSeparatedGenericEnumType::nullSafeSet] You cannot access to constructor of class : " + value.getClass(), e);
} catch (InvocationTargetException e) {
throw new MappingException("[CommaSeparatedGenericEnumType::nullSafeSet] InvocationTargetException for class : " + value.getClass(), e);
}
} else {
st.setNull(index, Types.VARCHAR);
throw new IllegalArgumentException();
}
}
}

Freemarker Debugger framework usage example

I have started working on a Freemarker Debugger using breakpoints etc. The supplied framework is based on java RMI. So far I get it to suspend at one breakpoint but then ... nothing.
Is there a very basic example setup for the serverpart and the client part other then the debug/imp classes supplied with the sources. That would be of great help.
this is my server class:
class DebuggerServer {
private final int port;
private final String templateName1;
private final Environment templateEnv;
private boolean stop = false;
public DebuggerServer(String templateName) throws IOException {
System.setProperty("freemarker.debug.password", "hello");
port = SecurityUtilities.getSystemProperty("freemarker.debug.port", Debugger.DEFAULT_PORT).intValue();
System.setProperty("freemarker.debug.password", "hello");
Configuration cfg = new Configuration();
// Some other recommended settings:
cfg.setIncompatibleImprovements(new Version(2, 3, 20));
cfg.setDefaultEncoding("UTF-8");
cfg.setLocale(Locale.US);
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Template template = cfg.getTemplate(templateName);
templateName1 = template.getName();
System.out.println("Debugging " + templateName1);
Map<String, Object> root = new HashMap();
Writer consoleWriter = new OutputStreamWriter(System.out);
templateEnv = new Environment(template, null, consoleWriter);
DebuggerService.registerTemplate(template);
}
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
startInternal();
}
}, "FreeMarker Debugger Server Acceptor").start();
}
private void startInternal() {
boolean handled = false;
while (!stop) {
List breakPoints = DebuggerService.getBreakpoints(templateName1);
for (int i = 0; i < breakPoints.size(); i++) {
try {
Breakpoint bp = (Breakpoint) breakPoints.get(i);
handled = DebuggerService.suspendEnvironment(templateEnv, templateName1, bp.getLine());
} catch (RemoteException e) {
System.err.println(e.getMessage());
}
}
}
}
public void stop() {
this.stop = true;
}
}
This is the client class:
class DebuggerClientHandler {
private final Debugger client;
private boolean stop = false;
public DebuggerClientHandler(String templateName) throws IOException {
// System.setProperty("freemarker.debug.password", "hello");
// System.setProperty("java.rmi.server.hostname", "192.168.2.160");
client = DebuggerClient.getDebugger(InetAddress.getByName("localhost"), Debugger.DEFAULT_PORT, "hello");
client.addDebuggerListener(environmentSuspendedEvent -> {
System.out.println("Break " + environmentSuspendedEvent.getName() + " at line " + environmentSuspendedEvent.getLine());
// environmentSuspendedEvent.getEnvironment().resume();
});
}
public void start() {
new Thread(new Runnable() {
#Override
public void run() {
startInternal();
}
}, "FreeMarker Debugger Server").start();
}
private void startInternal() {
while (!stop) {
}
}
public void stop() {
this.stop = true;
}
public void addBreakPoint(String s, int i) throws RemoteException {
Breakpoint bp = new Breakpoint(s, i);
List breakpoints = client.getBreakpoints();
client.addBreakpoint(bp);
}
}
Liferay IDE (https://github.com/liferay/liferay-ide) has FreeMarker template debug support (https://issues.liferay.com/browse/IDE-976), so somehow they managed to use it. I have never seen it in action though. Other than that, I'm not aware of anything that uses the debug API.

Spring Boot Return the Response Before the Process is Complete

I am using Spring Boot to process certificate and client postman to interact with service, assumption privatekey, publickey and certificate has been process decrypted, then using CertificateHelper getCertificate() function to parseX509Certificate
private List<Certificate> getCA(X509Certificate cert, Date tsp) {
Security.addProvider(new BouncyCastleProvider());
try {
String cnIssuer = X500Name.asX500Name(cert.getIssuerX500Principal()).getCommonName();
int xTry = 0;
while ((resultCA == null || resultCA_C5 == null || resultCA_C3 == null || resultCA_v1 == null) && xTry <= 3) {
LOGGER.info(LogSystem.getLog("TRY :" + xTry, tsp, "LOG"));
try {
loadCAinit();
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
xTry++;
}
if (xTry > 3) {
return null;
}
for (int i = 0; i < 4; i++) {
List<Certificate> CACheck;
if (i == 0) {
CACheck = resultCA;
} else if (i == 1) {
CACheck = resultCA_C3;
} else if (i == 2) {
CACheck = resultCA_C5;
} else {
CACheck = resultCA_v1;
}
LOGGER.info(LogSystem.getLog("CA CHECK : " + CACheck.get(0).toString(), tsp, "LOG"));
X509Certificate certCA;
try {
LogSystem.info("Process getcertificate on certificate helper");
certCA = (X509Certificate) CertificateHelper.getCertificate(CACheck.get(0).getCertificateData());
LogSystem.info("End process getcertificate on certificate helper");
String cnIssuerCheck = X500Name.asX500Name(certCA.getSubjectX500Principal()).getCommonName();
System.out.println(" CA CN: " + cnIssuerCheck);
System.out.println("User Issuer CN: " + cnIssuer);
if (cnIssuer.equals(cnIssuerCheck)) {
LOGGER.info(LogSystem.getLog("DN CA:" + certCA.getSubjectDN().toString() + ", SN: " + certCA.getSerialNumber().toString(16).toUpperCase(), tsp, "LOG"));
LOGGER.info(LogSystem.getLog("DN User:" + cert.getSubjectDN().toString() + ", SN: " + cert.getSerialNumber().toString(16).toUpperCase(), tsp, "LOG"));
return CACheck;
}
} catch (CertificateException e) {
// TODO Auto-generated catch block
LOGGER.info(LogSystem.getLog(" CATCH 1", tsp,"LOG"));
e.getCause();
e.printStackTrace();
System.out.println("asas");
}
}
LOGGER.info(LogSystem.getLog("Issuer " + cnIssuer + " not found : " + cert.getIssuerDN(), tsp, "LOG"));
System.out.println("asas");
} catch (IOException e) {
// TODO Auto-generated catch block
LOGGER.info(LogSystem.getLog(" CATCH 2", tsp,"LOG"));
e.printStackTrace();
System.out.println("asas");
}
LOGGER.info(LogSystem.getLog(" RETURN NULL", tsp,"LOG"));
System.out.println("asas");
return null;
}
getCertificate() function on class CertificateHelper
package org.ejbca.core.protocol.ws.common;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import org.cesecore.util.Base64;
import org.cesecore.util.CertTools;
public class CertificateHelper {
public static final String RESPONSETYPE_CERTIFICATE = "CERTIFICATE";
public static final String RESPONSETYPE_PKCS7 = "PKCS7";
public static final String RESPONSETYPE_PKCS7WITHCHAIN = "PKCS7WITHCHAIN";
public static final int CERT_REQ_TYPE_PKCS10 = 0;
public static final int CERT_REQ_TYPE_CRMF = 1;
public static final int CERT_REQ_TYPE_SPKAC = 2;
public static final int CERT_REQ_TYPE_PUBLICKEY = 3;
public CertificateHelper() {
}
public static Certificate getCertificate(byte[] certificateData) throws CertificateException {
Certificate retval = CertTools.getCertfromByteArray(Base64.decode(certificateData), Certificate.class);
return retval;
}
public static byte[] getPKCS7(byte[] pkcs7Data) {
return Base64.decode(pkcs7Data);
}
}
on getCertificate() function call another class CertTools function getCertfromByteArray()
public static <T extends Certificate> T getCertfromByteArray(byte[] cert, Class<T> returnType) throws CertificateParsingException {
return getCertfromByteArray(cert, "BC", returnType);
}
and detail function of getCertfromByteArray()
public static <T extends Certificate> T getCertfromByteArray(byte[] cert, String provider, Class<T> returnType) throws CertificateParsingException {
T ret = null;
String prov = provider;
if (provider == null) {
prov = "BC";
}
if (returnType.equals(X509Certificate.class)) {
ret = parseX509Certificate(prov, cert);
} else if (returnType.equals(CardVerifiableCertificate.class)) {
ret = parseCardVerifiableCertificate(prov, cert);
} else {
try {
ret = parseX509Certificate(prov, cert);
} catch (CertificateParsingException var8) {
try {
ret = parseCardVerifiableCertificate(prov, cert);
} catch (CertificateParsingException var7) {
throw new CertificateParsingException("No certificate could be parsed from byte array. See debug logs for details.");
}
}
}
return (Certificate)ret;
}
process on line 779 get log print
process on line 780 can't execution then client get returned response with http code 200
proses on line 781 not execution because on line 780
any suggestion why from line 780 give response to my postman with null body and http code success 200 ?
*Note class CertificateHelper and CertTools is library from official https://mvnrepository.com/artifact/org.ejbca

How to use Netty's channel pool map as a ConnectorProvider for a Jax RS client

I have wasted several hours trying to solve a issue with the use of netty's channel pool map and a jax rs client.
I have used jersey's own netty connector as an inspiration but exchanged netty's channel with netty's channel pool map.
https://jersey.github.io/apidocs/2.27/jersey/org/glassfish/jersey/netty/connector/NettyConnectorProvider.html
My problem is that I have references that I need inside my custom SimpleChannelInboundHandler. However by the design of netty's way to create a channel pool map, I can not pass the references through my custom ChannelPoolHandler, because as soon as the pool map has created a pool the constructor of the channel pool handler never runs again.
This is the method where it makes acquires a pool and check out a channel to make a HTTP request.
#Override
public Future<?> apply(ClientRequest request, AsyncConnectorCallback callback) {
final CompletableFuture<Object> completableFuture = new CompletableFuture<>();
try{
HttpRequest httpRequest = buildHttpRequest(request);
// guard against prematurely closed channel
final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> closeListener =
future -> {
if (!completableFuture.isDone()) {
completableFuture.completeExceptionally(new IOException("Channel closed."));
}
};
try {
ClientRequestDTO clientRequestDTO = new ClientRequestDTO(NettyChannelPoolConnector.this, request, completableFuture, callback);
dtoMap.putIfAbsent(request.getUri(), clientRequestDTO);
// Retrieves a channel pool for the given host
FixedChannelPool pool = this.poolMap.get(clientRequestDTO);
// Acquire a new channel from the pool
io.netty.util.concurrent.Future<Channel> f = pool.acquire();
f.addListener((FutureListener<Channel>) futureWrite -> {
//Succeeded with acquiring a channel
if (futureWrite.isSuccess()) {
Channel channel = futureWrite.getNow();
channel.closeFuture().addListener(closeListener);
try {
if(request.hasEntity()) {
channel.writeAndFlush(httpRequest);
final JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(channel);
request.setStreamProvider(contentLength -> jerseyChunkedInput);
if(HttpUtil.isTransferEncodingChunked(httpRequest)) {
channel.write(jerseyChunkedInput);
} else {
channel.write(jerseyChunkedInput);
}
executorService.execute(() -> {
channel.closeFuture().removeListener(closeListener);
try {
request.writeEntity();
} catch (IOException ex) {
callback.failure(ex);
completableFuture.completeExceptionally(ex);
}
});
channel.flush();
} else {
channel.closeFuture().removeListener(closeListener);
channel.writeAndFlush(httpRequest);
}
} catch (Exception ex) {
System.err.println("Failed to sync and flush http request" + ex.getLocalizedMessage());
}
pool.release(channel);
}
});
} catch (NullPointerException ex) {
System.err.println("Failed to acquire socket from pool " + ex.getLocalizedMessage());
}
} catch (Exception ex) {
completableFuture.completeExceptionally(ex);
return completableFuture;
}
return completableFuture;
}
This is my ChannelPoolHandler
public class SimpleChannelPoolHandler implements ChannelPoolHandler {
private ClientRequestDTO clientRequestDTO;
private boolean ssl;
private URI uri;
private int port;
SimpleChannelPoolHandler(URI uri) {
this.uri = uri;
if(uri != null) {
this.port = uri.getPort() != -1 ? uri.getPort() : "https".equals(uri.getScheme()) ? 443 : 80;
ssl = "https".equalsIgnoreCase(uri.getScheme());
}
}
#Override
public void channelReleased(Channel ch) throws Exception {
System.out.println("Channel released: " + ch.toString());
}
#Override
public void channelAcquired(Channel ch) throws Exception {
System.out.println("Channel acquired: " + ch.toString());
}
#Override
public void channelCreated(Channel ch) throws Exception {
System.out.println("Channel created: " + ch.toString());
int readTimeout = Integer.parseInt(ApplicationEnvironment.getInstance().get("READ_TIMEOUT"));
SocketChannelConfig channelConfig = (SocketChannelConfig) ch.config();
channelConfig.setConnectTimeoutMillis(2000);
ChannelPipeline channelPipeline = ch.pipeline();
if(ssl) {
SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
channelPipeline.addLast("ssl", sslContext.newHandler(ch.alloc(), uri.getHost(), this.port));
}
channelPipeline.addLast("client codec", new HttpClientCodec());
channelPipeline.addLast("chunked content writer",new ChunkedWriteHandler());
channelPipeline.addLast("content decompressor", new HttpContentDecompressor());
channelPipeline.addLast("read timeout", new ReadTimeoutHandler(readTimeout, TimeUnit.MILLISECONDS));
channelPipeline.addLast("business logic", new JerseyNettyClientHandler(this.uri));
}
}
And this is my SimpleInboundHandler
public class JerseyNettyClientHandler extends SimpleChannelInboundHandler<HttpObject> {
private final NettyChannelPoolConnector nettyChannelPoolConnector;
private final LinkedBlockingDeque<InputStream> isList = new LinkedBlockingDeque<>();
private final AsyncConnectorCallback asyncConnectorCallback;
private final ClientRequest jerseyRequest;
private final CompletableFuture future;
public JerseyNettyClientHandler(ClientRequestDto clientRequestDTO) {
this.nettyChannelPoolConnector = clientRequestDTO.getNettyChannelPoolConnector();
ClientRequestDTO cdto = clientRequestDTO.getNettyChannelPoolConnector().getDtoMap().get(clientRequestDTO.getClientRequest());
this.asyncConnectorCallback = cdto.getCallback();
this.jerseyRequest = cdto.getClientRequest();
this.future = cdto.getFuture();
}
#Override
protected void channelRead0(ChannelHandlerContext ctx, HttpObject msg) throws Exception {
if(msg instanceof HttpResponse) {
final HttpResponse httpResponse = (HttpResponse) msg;
final ClientResponse response = new ClientResponse(new Response.StatusType() {
#Override
public int getStatusCode() {
return httpResponse.status().code();
}
#Override
public Response.Status.Family getFamily() {
return Response.Status.Family.familyOf(httpResponse.status().code());
}
#Override
public String getReasonPhrase() {
return httpResponse.status().reasonPhrase();
}
}, jerseyRequest);
for (Map.Entry<String, String> entry : httpResponse.headers().entries()) {
response.getHeaders().add(entry.getKey(), entry.getValue());
}
if((httpResponse.headers().contains(HttpHeaderNames.CONTENT_LENGTH) && HttpUtil.getContentLength(httpResponse) > 0) || HttpUtil.isTransferEncodingChunked(httpResponse)) {
ctx.channel().closeFuture().addListener(future -> isList.add(NettyInputStream.END_OF_INPUT_ERROR));
response.setEntityStream(new NettyInputStream(isList));
} else {
response.setEntityStream(new InputStream() {
#Override
public int read() {
return -1;
}
});
}
if(asyncConnectorCallback != null) {
nettyChannelPoolConnector.executorService.execute(() -> {
asyncConnectorCallback.response(response);
future.complete(response);
});
}
}
if(msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf byteContent = content.content();
if(byteContent.isReadable()) {
byte[] bytes = new byte[byteContent.readableBytes()];
byteContent.getBytes(byteContent.readerIndex(), bytes);
isList.add(new ByteArrayInputStream(bytes));
}
}
if(msg instanceof LastHttpContent) {
isList.add(NettyInputStream.END_OF_INPUT);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if(asyncConnectorCallback != null) {
nettyChannelPoolConnector.executorService.execute(() -> asyncConnectorCallback.failure(cause));
}
future.completeExceptionally(cause);
isList.add(NettyInputStream.END_OF_INPUT_ERROR);
}
The references needed to be passed to the SimpleChannelInboundHandler is what is packed into the ClientRequestDTO as seen in the first code block.
I am not sure as it is not a tested code. But it could be achieved by the following code.
SimpleChannelPool sPool = poolMap.get(Req.getAddress());
Future<Channel> f = sPool.acquire();
f.get().pipeline().addLast("inbound", new NettyClientInBoundHandler(Req, jbContext, ReportData));
f.addListener(new NettyClientFutureListener(this.Req, sPool));
where Req, jbContext, ReportData could be input data for InboundHandler().

Resources