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?
Related
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.
I am facing the problem of finding the best place to put some handling where I can check some of the properties in application.yml and fail app startup of Spring Boot app if they are invalid.
The main point is to find the first place where I can check these properties without running the entire app and fail in the end.
I tried:
#EventListener, but here I was able only to trigger events when the app was started.
Throwing an exception in #PostConstruct in one of my classes with #Configuration. I like this one, but it looks like a messy one.
Maybe there are better ways?
#EventListener, but here I was able only to trigger events when the
app was started
There are many different type of events and where you hook in to the startup process depends on the type of event that you listen for. In your case, consider listening for an ApplicationEnvironmentPreparedEvent if you want to check properties as soon as they are available.
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.
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.
According to Spring documentation, it's possible to configure an embedded ApacheDS server, which makes testing easy.
Any reason why not use ApacheDS embedded with spring in deployment? is there some kind of limitation for that?
Also I noticed it's writing to temp directory /tmp/apacheds-spring-security. Is there a way to configure it?
I already participated in a project where embedded ApacheDS server was used in development and deployment (for test server). There was two minor problems:
If you stop your app incorrectly (for example via Terminate in debug mode or via kill -9) then you need to clean up /tmp/apacheds-spring-security directory manually. If you leave temporary files then an runtime exception will be thrown during next loading of your app.
We did not find how to change the default temporary directory (/tmp/apacheds-spring-security).
Hope this helps.
EDIT.
For the first problem I ended up with a servlet-api listener. It was declared before Spring context listener (to ensure execution before Spring and ApacheDS). This listener was responsible for checking and cleaning up /tmp/apacheds-spring-security. Maybe it is not the most elegant solution but it works. It will be better to have a param for this case in ApacheDS, something like -DapacheDSCleanUpWorkDirAtStutup=true.