how dynamic create ftp adapter in spring integration? - java

Thanks for attention
i used spring integration in my project, i want to retrieve many input file from multiple ftp server with different address as bellow image:
how to create dynamically inbound-adapter in my project to polling and retrieve files from servers?

If you're allowed to use non-"General Availability" (GA) versions of 3rd party libraries (e.g. release candidates (RC) or milestones (M)) in your project, then you can utilize version 5.0.0.M2 of Spring Integration. It is the latest published version as of Mar 09 '17.
Starting from 5.0, Spring Integration includes Java DSL Runtime flow registration feature. It allows you to define integration flows (including inbound adapters) just like you do it in standard beans but it can be done at any runtime moment.
All you need to use it are these 3 steps:
Get IntegrationFlowContext bean from Spring context, e.g. by means of autowiring:
#Autowired
public MyClass(IntegrationFlowContext flowContext) {
this.flowContext = flowContext;
}
Build new flow with it, for example:
IntegrationFlowRegistration registration = flowContext
.registration(IntegrationFlows // this method accepts IntegrationFlow instance
.from(s -> s.ftp(ftpSessionFactory())
.localFilter(localFileFilter())
//other actions
.get()) // standard end of DSL flow building process
.autoStartup(true) // not required but can be useful
.register(); // this makes the flow exist in the context
When it's time to remove dynamically created flow, just refer to IntegrationFlowContext again with registration id you've got in the previous step:
// retrieve registration ID from the object created above
String dynamicFlowRegistrationId = registration.getId();
// the following will also gracefully stop all the processes within the flow
flowContext.remove(dynamicFlowRegistrationId);
There is also a DynamicTcpClient sample available on GitHub.

See the dynamic-ftp sample. While it only covers the outbound side, there are links in the README to discussions about what needs to be done on the inbound side (put each adapter in a child context that send messages to a channel in the main context).
Also see my answer to a similar question for multiple IMAP mail adapters using Java configuration and then a follow-up question.
You should be able to use the technique used there.

Related

How to integrate GraphiQL with Spring-Boot?

My target is to build a GraphQL server on Spring with (1) GraphiQL IDE (2) dynamic GraphQL schema at run-time. My GraphQL engine is GraphQL-Java.
In my first try, I use graphql-java-spring-boot-starter-webmvc and graphiql-spring-boot-starter.
Both the GraphQL server and the GraphiQL work well.
However, under the graphql-java-spring-boot-starter-webmvc framework, a #Bean of GraphQL class is needed. In this bean, the schema is loaded when the server starts so it could not been updated.
In my second try, I don't use graphql-java-spring-boot-starter-webmvc. Instead, I choose spring-boot-starter-web to start the web server and define my own RestController. This is easy to update the GraphQL instance. But I don't find a way to integrate with GraphiQL. I googled GraphiQL+Spring but all solutions are with graphql-java-spring-boot-starter.
Appreciate if anyone could provide me an idea on either approach.
It can be enabled in properties:
graphql.graphiql.enabled=true
It is accessible via the root url +/graphiql example http://localhost:8080/graphiql
You can find a good detailed example here : https://github.com/NoorKrichen/GraphQL-Spring-Boot-Example
Do you have a sample of your setup in git?
It sounds like some configuration problem. But naturally using graphql-java-spring-boot-starter-webmvc all your *.graphql schemas should be picked up in the configured schema resource path. check if you have the path set in your application.yml or if your schema is in the configured path if its already set or by default.
On your second point: "I googled GraphiQL+Spring but all solutions are with graphql-java-spring-boot-starter."
This makes sense for quick guides and demos as using Springboot the plumbing is somehow hidden away from you so that you can focus on the technology at hand being demo'd in this case GraphQl.
On GraphiQL:
Sounds like you are intending to have this embedded with your application, you may not want to do so in production. Depending on your use case there are many other alternatives that are standalone and gives you all the functionality of GraphiQL plus more e.g Altair Graphql Client and Insomnia to name a few.

Start Spring Integration route on demand, not during context initialization

I have a Spring Integration route (made via DSL) that polls the files from a specific folder (as shown in Polling from file using Java DSL - compile error when adding Files.inboundAdapter) and sends to Rabbit.
When I configured the flow as explained in the link above, it starts on configuration stage already. I, however, would like to start it in runtime, later, since I need to connect to Rabbit first.
How can I configure IntegrationFlow to be started/stopped later on demand?
Add autoStartup(false).
e -> e.poller(Pollers.fixedDelay(5000))
.autoStartup(false)
then flow.start() when you are ready.

Dynamic Spring Boot-Integration configuration

I would like to migrate a multi-threaded application in JSE to Spring Integration but I have to clarify some points before. First of all, the application will have the following Spring integration components:
JMS to Transformer to router to TCPOut
TcpIn (to router) to Transformer to JMS
In this context, I have to load all the TCP connections dynamically from a configuration file. I saw a couple of example of this here in StackOverflow (based in the FTP sample). These samples could be enough for the first part but I am looking for how to do that in Spring Boot and what is the best (and elegant) way to create this type of configuration.
Finally, I have to access to each different context (this is maybe the most important) from a type of Swing monitor to start/stop manually this TCP connections. Is this possible? What do you suggest me to do?
All my current components are java based configuration (not DSL).
See my answers to this question and its follow-up for examples of how to dynamically create application contexts using Java Configuration.
Also, take a look at the new feature in the Java DSL for dynamically registering/removing integration flows with the context. The 1.2 version of the DSL, containing this feature, will be released shortly.
You can stop/start endpoints using JMX or a control bus, or programmatically.

Dropwizard - Resources on multiple ports

I have a Dropwizard(v 0.7.1) based Jersey REST service. Currently I use one application connector port (8810) and I have two resources (say "/path1","/path2").
I will be able to access these resources as http:\\localhost:8810\path1 and http:\\localhost:8810\path2 respectively. What am trying to achieve is have a separate port for each resource. (e.g http:\\localhost:8810\path1 and http:\\localhost:8820\path2). I tweaked the yaml file to have the below configuration and when I started the application both resources were available using both ports and am not sure how to configure these resources to use specific ports or is that even possible with Dropwizard?
server:
applicationConnectors:
-
type: http
port: 8810
-
type: http
port: 8820
Appreciate if someone can enlighten.
Thanks
your issue is that the DefaultServerFactory adds all applicationConntectors to the same Handler, see DefaultServerFactory#build:
#Override
public Server build(Environment environment) {
printBanner(environment.getName());
final ThreadPool threadPool = createThreadPool(environment.metrics());
final Server server = buildServer(environment.lifecycle(), threadPool);
LOGGER.info("Registering jersey handler with root path prefix: {}", applicationContextPath);
environment.getApplicationContext().setContextPath(applicationContextPath);
final Handler applicationHandler = createAppServlet(server,
environment.jersey(),
environment.getObjectMapper(),
environment.getValidator(),
environment.getApplicationContext(),
environment.getJerseyServletContainer(),
environment.metrics());
LOGGER.info("Registering admin handler with root path prefix: {}", adminContextPath);
environment.getAdminContext().setContextPath(adminContextPath);
final Handler adminHandler = createAdminServlet(server,
environment.getAdminContext(),
environment.metrics(),
environment.healthChecks());
final RoutingHandler routingHandler = buildRoutingHandler(environment.metrics(),
server,
applicationHandler,
adminHandler);
server.setHandler(addStatsHandler(addRequestLog(server, routingHandler, environment.getName())));
return server;
}
What you need to do is implement your own ServerFactory.
You can extend DefaultServerFactory and overwrite the build method to set up your connectors in the way you want them to be.
Presumably you'll want to add some more configuration that indicates what goes where, since in terms of your yaml it will not be possible to map a resource to a specific connector. How would dropwizard know about that.
For overwriting the behaviour for dropwizard (adding a new ServerFactory) you can see this post I wrote about adding logging: Dropwizard doesn't log custom loggers to file
It basically involves implementing the class and making it discoverable for dropwizard. After that all you need to do is to change the yaml file to point to the correct ServerFactory.
If you don't like that approach, you can overwrite the get/set method on the configuration to return your class. For this, your class MUST extend DefaultServerFactory, since otherwise the yaml mapping won't work anymore. You can overwrite the build method regardless though.
Update:
Looking at it in a bit more detail, you'll run into a second problem:
Your Environment only has one jersey environment that it can use.
You will need to configure a second jersey environment since currently by default each Handler will get the same Jersey config passed to it (the only one that exists). This is why it will be available for all of your http configurations. So in summary:
Create a new Environment that supports multiple jersey configurations
Create a server factory that knows what jersey config belongs to which Handler and instantiates the handlers in that form.
I believe those two steps would be required.
In terms of environment, you will have to create your own ServerCommand (that is the command that starts up dropwizard server).
Looking in EnvironmentCommand#run you can see where the Environment is created. This will be the only place you can overwrite the default Environment (as far as I know) which is what you need to do to support multiple jersey configs.
To be honest with you, looking at this, I do not believe that this is what the dropwizard guys had in mind.

CamelContext doesn't startup if one route is misconfigured

We use Java DSL to configure our routes. All configurations for routes are in a db table and can be configured via a GUI.
How is it possible to ensure that the camelContext starts up even if a route is misconfigured (e.g. .to(invalidurl or typo) in a route or simply a bug in a route)?
Is there a possibilty to validate the routes before starting or maybe better some parameters/options which can be set on the context itself?
You can configure the routes with .autoStartup(false), and then start the routes manually when CamelContext has been started up.
To validate its really depending on what kind of component it is. If its some database component you can write some code that does a SQL query to see if the is valid user login or something.
To validate that an endpoint uri is misconfigured, then that is harder as they have a ton of options. But this is getting improved from Camel 2.16 onwards where we have during build time some tooling that generates a json schema file with the options, then we could potentially leverage that during parsing the routes to check for invalid configuration before attempting to create the endpoints which could detect errors sooner, and even also with IDE plugins or other 3rd party tooling.
Can you just before adding every route to the context, add it to a separate "test" context individually, and see if it spins up or fails; then based on that add it to your real context?

Categories

Resources