Dynamic TCP Server with Spring Integration using Java DSL - java

I am trying to create a TCP server and client by reading the property files which contains the detail of the connections.
I am using Dynamic and runtime Integration Flows with the help of following reference document (
9.20 Dynamic and runtime Integration Flows)
The code is working fine while creating the client but when I am creating the server using the same with changes in the code as follow:
IntegrationFlow flow = f -> f
.handle(Tcp.inboundAdapter(Tcp.netServer(2221)
.serializer(TcpCodecs.crlf())
.deserializer(TcpCodecs.lengthHeader1())
.id("server")))
.transform(Transformers.objectToString());
IntegrationFlowRegistration theFlow = this.flowContext.registration(flow).register();
I am getting the following error:
Caused by: java.lang.IllegalArgumentException: Found ambiguous parameter type [class java.lang.String] for method match: [public java.lang.Class<?> org.springframework.integration.dsl.IntegrationComponentSpec.getObjectType(), public S org.springframework.integration.dsl.MessageProducerSpec.outputChannel(java.lang.String), public S org.springframework.integration.dsl.MessageProducerSpec.outputChannel(org.springframework.messaging.MessageChannel), public org.springframework.integration.ip.dsl.TcpInboundChannelAdapterSpec org.springframework.integration.ip.dsl.TcpInboundChannelAdapterSpec.taskScheduler(org.springframework.scheduling.TaskScheduler), public S org.springframework.integration.dsl.MessageProducerSpec.errorMessageStrategy(org.springframework.integration.support.ErrorMessageStrategy), public S org.springframework.integration.dsl.MessageProducerSpec.phase(int), public S org.springframework.integration.dsl.MessageProducerSpec.autoStartup(boolean), public S org.springframework.integration.dsl.MessageProducerSpec.sendTimeout(long)]
at org.springframework.util.Assert.isNull(Assert.java:155)
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:843)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:362)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:231)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:225)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:60)
at org.springframework.integration.handler.ServiceActivatingHandler.<init>(ServiceActivatingHandler.java:38)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:924)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:904)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:891)
at org.springframework.integration.samples.dynamictcp.DynamicTcpClientApplication.lambda$1(DynamicTcpClientApplication.java:194)
at org.springframework.integration.config.dsl.IntegrationFlowBeanPostProcessor.processIntegrationFlowImpl(IntegrationFlowBeanPostProcessor.java:268)
at org.springframework.integration.config.dsl.IntegrationFlowBeanPostProcessor.postProcessBeforeInitialization(IntegrationFlowBeanPostProcessor.java:96)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:423)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1702)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
... 16 common frames omitted
Please help me with above issue.
Also I have found the code for dynamic tcp client but no code is present for dynamic tcp server(any resource or link where I can take an idea to create dynamic server).

You are mixing responsibility. The Tcp.inboundAdapter() must be a first in the IntegrationFlow chain. Consider to use this instead:
IntegrationFlow flow =
IntegrationFlows.from(Tcp.inboundAdapter(Tcp.netServer(2221)
.serializer(TcpCodecs.crlf())
.deserializer(TcpCodecs.lengthHeader1())
.id("server")))
.transform(Transformers.objectToString())
.get();

Related

Not able to create a connection to Janus to define the schema

Not able to create a connection to Janus to define the schema.
JanusGraph graph = JanusGraphFactory.build().set("storage.backend", "cql")//.set("storage.cql.keyspace", "janusgraph")
.set("storage.hostname", "url").open();
Error:
java.lang.IllegalArgumentException: Could not find implementation class: org.janusgraph.diskstorage.cql.CQLStoreManager
at org.janusgraph.util.system.ConfigurationUtil.instantiate(ConfigurationUtil.java:75)
at org.janusgraph.diskstorage.Backend.getImplementationClass(Backend.java:530)
at org.janusgraph.diskstorage.Backend.getStorageManager(Backend.java:494)
Able to do normal tinkerpop gremlin query with the following config
#Bean
public Cluster cluster() {
return Cluster.build()
.addContactPoint(dbUrl)
.port(dbPort)
.serializer(new GraphBinaryMessageSerializerV1())
.maxConnectionPoolSize(5)
.maxInProcessPerConnection(1)
.maxSimultaneousUsagePerConnection(10)
.create();
}
#Bean
public GraphTraversalSource g(Cluster cluster) throws Exception {
//return traversal().withRemote(DriverRemoteConnection.using(cluster));
return traversal().withRemote("conf/remote-graph.properties");
}
Want to define the schema during the application start up, Trying to use openManagement
When writing a java application using janusgraph, you can choose between embedding janusgraph in your application or connecting to a janusgraph server. Your code suggests you are attempting the embedded option, so you can start from the example in the provided link.

Why Spring Integration message method handling behavoiur is changed in default Spring Cloud Stream configuration

I have an application where Spring Integration (5.1.6 latest) is already used. And something like the following flow configured:
#Configuration
public class SomeConfigClass {
...
#MessagingGateway(name = "someGateway")
interface Gateway {
#Gateway(requestChannel = "inboundChannel")
#Payload("T(java.time.ZonedDateTime).now()")
void replicate();
}
#Bean
public DirectChannel inboundChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow someFlow() {
return IntegrationFlows.from(inboundChannel())
.handle(someHandler())
.channel(OUT)
.get();
}
#Bean
public SomeHandler someHandler() {
return new SomeHandler();
}
}
and
public class SomeHandler implements GenericHandler<Object> {
#Override
public Message<List<String>> handle(final Object payload,
final MessageHeaders headers) {
...
return MessageBuilder
.withPayload(someList)
.copyHeaders(headers)
.setHeader("custom", customHeader)
.build();
}
}
Everything works fine.
And if I try to find integrationArgumentResolverMessageConverter bean in context initialised I see next converters:
MappingJackson2MessageConverter
ByteArrayMessageConverter
ObjectStringMessageConverter
GenericMessageConverter
After that I add to my pom dependencies Spring Cloud Stream 2.1.2 dependency and Kinesis Binder 1.2.0. Configure bindings by default.
The application starts up but when I trying to process my existing flow it failed with something like:
EL1004E: Method call: Method handle(java.time.ZonedDateTime,org.springframework.messaging.MessageHeaders) cannot be found on type p.a.c.k.a.g.e.SomeHandler at org.springframework.expression.spel.ast.MethodReference.findAccessorForMethod(MethodReference.java:225)
at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:134)
at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:54)
at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:390)
at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:90)
at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:114)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:365)
at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:172)
at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:160)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.invokeExpression(MessagingMethodInvokerHelper.java:664)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.invokeHandlerMethod(MessagingMethodInvokerHelper.java:655)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:491)
at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:362)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:106)
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:93)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:123)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:169)
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115)
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:132)
at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:105)
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:73)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:453)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:401)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:187)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:166)
at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:47)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:109)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:151)
at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:143)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:413)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:533)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:473)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:463)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
at com.sun.proxy.$Proxy444.replicate(Unknown Source)
And when I try to get the same integrationArgumentResolverMessageConverter bean from initialized context I see next chain:
ApplicationJsonMessageMarshallingConverter
TupleJsonMessageConverter
ByteArrayMessageConverter
ObjectStringMessageConverter
JavaSerializationMessageConverter
KryoMessageConverter
JsonUnmarshallingConverter
And there is no GenericMessageConverter. As I understand it cannot be converted because of this converter missed (correct me please if I am wrong).
Why is the behaviour different when I just add Spring Cloud Stream default configuration? Or how to customize of using converters chain for specific flow? Or how to keep message conversation behaviour for different integration flow?
Update: So as I investigated spring cloud stream re-defines not only default integration MessageConverters, but also it re-defines default HandlerMethodArgumentResolvers, which is used to map method argument with a message..
Before additing Spring Cloud Stream:
HeaderMethodArgumentResolver
HeadersMethodArgumentResolver
MessageMethodArgumentResolver
PayloadExpressionArgumentResolver
NullAwarePayloadArgumentResolver
PayloadsArgumentResolver
MapArgumentResolver
PayloadArgumentResolver
After additing Spring Cloud Stream:
SmartPayloadArgumentResolver
SmartMessageMethodArgumentResolver
HeaderMethodArgumentResolver
HeadersMethodArgumentResolver
PayloadExpressionArgumentResolver
NullAwarePayloadArgumentResolver
PayloadExpressionArgumentResolver
PayloadsArgumentResolver
MapArgumentResolver
There two deprecated SmartPayloadArgumentResolver and SmartMessageMethodArgumentResolver with fix for conversion from byte[] payload to Object. But what I cannot understand why there are two PayloadExpressionArgumentResolver?..
And the main question: why Spring Cloud Stream default application context affects Spring Integration default application context, I thought before that Stream's resolvers/converters were only related to message endpoints linked with stream destination channels...
I am not sure why Stream drops that converter (could be a bug, maybe open a GitHub issue over there), but I believe you can add it back as a #StreamMessageConverter #Bean as discussed in the stream docs.
After investigation I can make assumption that the behaviour of method message handling is changed because of Spring Cloud Stream's issue and corresponding Spring Framework's issue. There is temporary overriden argument resolvers initialization in Spring Binder auto-configuration (bean definition on static method BinderFactoryConfiguration#messageHandlerMethodFactory).
So first resolver in chain is SmartPayloadArgumentResolver which decides that the conversation is needed. This conversation is started and failed by ApplicationJsonMessageMarshallingConverter. The exception:
org.springframework.messaging.converter.MessageConversionException: Could not read JSON: Unexpected character ('-' (code 45)): Expected space separating root-level values
at [Source: (String)"2019-09-04T01:26:20.202Z[UTC]"; line: 1, column: 6]; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('-' (code 45)): Expected space separating root-level values
at [Source: (String)"2019-09-04T01:26:20.202Z[UTC]"; line: 1, column: 6], failedMessage=GenericMessage [payload=2019-09-04T01:26:20.202Z[UTC], headers={spanTraceId=3f87b9afc373308a, spanId=3f87b9afc373308a, nativeHeaders={spanTraceId=[3f87b9afc373308a], spanId=[3f87b9afc373308a], spanSampled=[1]}, X-B3-SpanId=3f87b9afc373308a, X-B3-Sampled=1, X-B3-TraceId=3f87b9afc373308a, id=3fbe87e3-31c4-4d21-c3fb-506c018c0e25, spanSampled=1, timestamp=1567560380202}]
And as result I face error aforementioned in the question thrown from MethodReference.

How to create channels with Spring 4 annotation based?

I want to create a socket channel with a rendezvous queue where a client and server can exchange a simple message.
But I already fail to convert the following xml to annotation based spring-4 configuration:
<int:channel id="rendezvousChannel"/>
<int:rendezvous-queue/>
</int:channel>
How would this look like in spring 4?
The short answer:
#Bean
public PollableChannel rendezvousChannel() {
return new RendezvousChannel();
}
Can you explain why it was an issue for you to find the solution from your side?
Any XML component is backed by some Java class anyway and most cases their names reflect the XML component names.

No bean named but bean is defined

I'm working on an update version of grail-oauth-plugin that support last spring-oauth
My plugin version works good and I have implemented a workin oauth2 server.
But now I want to add a custom-grant defined like this
def doWithSpring = {
myTokenGranter(MyTokenGranter)
xmlns oauth:"http://www.springframework.org/schema/security/oauth2"
oauth.'authorization-server'( /* ... many definitions here ... */){
/* ... many definitions here ... */
oauth.'custom-grant'('token-granter-ref': "myTokenGranter")
}
}
But I get an exception telling me:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myTokenGranter'
But the bean myTokenGranter is defined as you can see. And If I remove the custom-grant definition the project starts and I can access the myTokenGranter bean.
Looking to a fullstack trace I see that the exception occur in the spring oatuh2 server bean definition parse AuthorizationServerBeanDefinitionParser.java in the line where it try to find my bean
parserContext.getRegistry().getBeanDefinition(customGranterRef);
where customGranterRef = "myTokenGranter"
so I suspect there is a bug in Spring Ouath or in Grails BeanBuilder that does not let my "myTokenGranter" to be visible in the server parser. Or making some error in grails bean definition DSL.
Thank you for your interest.
Debugging the app more deeply I have found that the problem probably is in how grails BeanBuilder work in translating namespaced spring DSL.
If I debug the point where my bean is checked (in AuthorizationServerBeanDefinitionParser.java)
at row
parserContext.getRegistry().getBeanDefinition(customGranterRef);
if I check che result of
parserContext.getRegistry().getBeanDefinitionNames()
it show me only this beans
[org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalPersistenceAnnotationProcessor
org.springframework.aop.config.internalAutoProxyCreator
org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#0
org.springframework.transaction.interceptor.TransactionInterceptor#0
org.springframework.transaction.config.internalTransactionAdvisor
oauth2TokenGranter
oauth2AuthorizationCodeServices
oauth2AuthorizationRequestManager]
And not all other decleared beans...
The problem exist even if I move the ouath server declaration inside resources.xml, keeping my custom token granter bean declaration inside resources.groovy.
But the problem solves if I move the custom token bean declaration inside resources.xml.
I don't really know how the BeanBuilder DSL works, but it seems like the problem is there if there is a problem (your example works just fine in XML). Can you do it in two steps, so the bean definition for myTokenGranter is definitely available when the OAuth2 namepsace is handled?
Solved hacking Spring Security Oauth
see this commit

Accesing an remote enterprise bean within a simple Java class

Here's my Java class
import endpoint.NewSessionRemote;
import javax.naming.Context;
import javax.naming.InitialContext;
public class HelloClient {
public static void main(String[] args) {
try {
Context ctx = new InitialContext();
NewSessionRemote hello = (NewSessionRemote) ctx.lookup("endpoint.NewSessionRemote");
System.out.println(hello.stringChange(4));
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
When I run this class I'm getting an exception.
javax.naming.NameNotFoundException: endpoint.NewSessionRemote not found
at com.sun.enterprise.naming.TransientContext.doLookup(TransientContext.java:216)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:188)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:74)
at com.sun.enterprise.naming.RemoteSerialContextProviderImpl.lookup(RemoteSerialContextProviderImpl.java:129)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)
java.lang.NullPointerException
All the other enterprise bean classes are written according to the EJB 3.0 standard.
Your valuable contribution is expected.
Solution
The exception was
javax.naming.NameNotFoundException: endpoint.NewSessionRemote not found
It occurs because the JNDI name that was given by the application side didn't match the servser's (Glassfish) actual JNDI name, so I did was check the JNDI tree in Glassish through its admin console (vendor specific) and I did notice that the JNDI for the NewSessionRemote interface (which is the business interface of the session bean NewSessionBean) is different from the name which I have given in the application side. So how did this happen then suddenly something came in to my mind that's the ejb-jar.xml there is another name JNDI name assigned to the same NewSessionRemote using tag. So I simply remove it and redeploy EJB module. That's it.
Looks like you have no RMI registry (i.e. active server) you are lookingUp() against.
You supplied no Context.INITIAL_CONTEXT_FACTORY variable, so the lookup should be a valid URL, which it is not.
Hence, you should put something like this on your env (on the iCtx):
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
I suggest you read the the simple examples over at http://java.sun.com/j2se/1.5.0/docs/guide/jndi/jndi-rmi.html
When using JNDI, you're using an API that requires a specific configuration underlying it in order to connect to the server (see the Javadoc for details on what that configuration is). For example, java.naming.factory.initial is the property which indicates which implementation of JNDI you want to use.
Now, when running code inside a JavaEE server, this configuration is available implicitly, and all you need to do is what you have done in your code - instantiate InitialContext, and perform a lookup. However, when running outside the server, this implicit configuration is not present, and so you need to configure your InitialContext explicitly.
Your sample code uses a main() method, which suggests that you're running outside the container. The config you need will depend on your specific application server, you'll need to look up that documentation to see what config to supply.

Categories