Camel - How to change destination(to) when processing a file(processor) - spring-boot

I have a spring boot application and with camel I read a file using FTP, I process the file and move that file to another location, my problem is that I need to change the destination depending of the file name. I read that I can use "toD" and use property placeholder to change the destination dynamically but I don't know how to set that value from the processor or is even possible to do that?,
Here is my main class:
#Component
public class Controlador extends RouteBuilder {
#Autowired
Procesador objProcesador;
#Override
public void configure() throws Exception {
from("ftp://user#ip:21?password=mypassword&passiveMode=true&delete=true").streamCaching().convertBodyTo(InputStream.class).process(objProcesador).to("file:C:\\Users\\juan.gaytan\\Desktop\\prueba2");
}
}
And here is my Processor class:
#Service
public class Procesador implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
}
}
Thanks in advance.

You could use Simple as explained here.
An example would be to set the destination in exchange header as
exchange.getOut().setHeader("uri", destination);
and use in route as below
<toD uri="${header.uri}"/>

Related

Apache camel dynamic routing

I have following Apache camel rest service(/sales) that internally calls another rest service(/getOrders) and get list of objects. Am able to print JSON response in the processor but getting java objects in response while trying from postman. Could anyone pls help me to resolve the issue. Attaching the response log for ref..
#Component
public class ApplicationResource extends RouteBuilder {
#Autowired
private OrderService service;
#BeanInject
private OrderProcessor processor;
#Override
public void configure() throws Exception {
restConfiguration().component("servlet").port(9090).host("localhost");
rest().get("/getOrders").produces(MediaType.APPLICATION_JSON_VALUE).route().setBody(() -> service.getOrders());
rest().get("/sales").produces(MediaType.APPLICATION_JSON_VALUE).route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true").convertBodyTo(String.class).marshal()
.json(JsonLibrary.Jackson, Order.class).to("log:foo?showHeaders=true");;
;
}
}
You should remove the last .endRest() on "direct:bye" route.
I think you get the rest response before calling your Processor.
This works for me.
First, I needed to set the bindingMode as RestBindingMode.json in the restConfiguration.
Secondly, instead of marshal(), you need to use unmarshal().
Third, since you are returning a list of orders, .json(JsonLibrary.Jackson, Order.class) will not be sufficient to unmarshal the list of orders. You need to use a custom format which will be able to unmarshal the list of orders into a json array. This you need to do using JacksonDataFormat format = new ListJacksonDataFormat(Order.class);
#Override
public void configure() {
JacksonDataFormat format = new ListJacksonDataFormat(Order.class);
restConfiguration().component("servlet").port(9090).host(localhost).bindingMode(RestBindingMode.json);
rest()
.get("/getOrders")
.produces(MediaType.APPLICATION_JSON_VALUE)
.route()
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
exchange.getMessage().setBody(service.getOrders());
}})
.to("log:getOrders?showHeaders=true&showBody=true");
rest()
.get("/sales")
.produces(MediaType.APPLICATION_JSON_VALUE)
.route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true")
.unmarshal(format)
.to("log:sales?showHeaders=true&showBody=true");
}
Solvedddd !!! i did two things as follows,May be use full for some one
1,bindingMode(RestBindingMode.auto) - RestBindingMode changes to auto
from json
2, Added this in the main
service(/getOrders).marshal().json(JsonLibrary.Jackson);
#Component
public class ApplicationResource extends RouteBuilder {
#Autowired
private OrderService service;
#BeanInject
private OrderProcessor processor;
#Override
public void configure() throws Exception {
restConfiguration().component("servlet").port(9090).host("localhost").bindingMode(RestBindingMode.auto);
rest().get("/getOrders").produces(MediaType.APPLICATION_JSON_VALUE).route().setBody(() -> service.getOrders())
.marshal().json(JsonLibrary.Jackson);
rest().get("/sales").produces(MediaType.APPLICATION_JSON_VALUE).route()
.setHeader(Exchange.CONTENT_TYPE, constant("application/json"))
.toD("http://localhost:9090/getOrders?bridgeEndpoint=true").convertBodyTo(String.class)
.log("body = ${body}");
;
;
}
}

spring-statemachine 2.3.1 - How to get a StateMachine from a StateMachineModelFactory?

I'm having the following business case while working with spring-statemachine 2.3.1 in a project:
The state machine is defined with the Papyrus plugin and loaded from an uml file using the UmlStateMachineModelFactory as shown below:
public class MyStateMachineConfig extends StateMachineConfigurerAdapter<String, String>
{
#Override
public void configure(StateMachineModelConfigurer<String, String> model) throws Exception
{
model.withModel().factory(myStateMachineModelFactory());
}
#Bean
public StateMachineModelFactory<String, String> myStateMachineModelFactory()
{
return new UmlStateMachineModelFactory("classpath:my.uml");
}
....
I need to persist the state machine context in a database using JPA. In order to do this, I need to use StateMachinePersister.persist(). This method uses as its first input parameter a StateMachine instance. However, I'm not able to get the StateMachine instance from my StateMachineModelFactory. The class StateMachineFactory has a method named getStateMachine() while the class StateMachineModelFactory doesn't.
I didn't find neither a way to get a StateMachineFactory instance from a StateMachineModelFactory instance. Could anyone please help with some suggestions, ideally examples ? The documentation has different examples of how to do it but none for the case when the state machine is loaded from an UML file.
Kind regards,
Nicolas DUMINIL
Your configuration for StateMachineFactory should look like below
#Configuration
#EnableStateMachineFactory
public static class SsmConfig
extends EnumStateMachineConfigurerAdapter<States, Events> {
#Override
public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
states
.withStates()
.initial(States.S1)
.end(States.SF)
.states(EnumSet.allOf(States.class));
}
}
And then you can simply inject StateMachineFactory everywhere and just get state machine.
class SomeService {
#Autowired
private StateMachineFactory<States, Events> factory;
void method() {
StateMachine<States,Events> stateMachine = factory.getStateMachine();
stateMachine.start();
}
}
More information can be found here.
Your configuration, which extends StateMachineConfigurerAdapter is an "adaptation" or modification of the auto-configured Spring state machine.
In order for your configuration to be picked-up by spring you need to annotate it with #Configuration.
You also have to enable the State Machine auto-configuration, which happens with #EnableStateMachie annotation.
#Configuration
#EnableStateMachine
public class MyStateMachineConfig extends StateMachineConfigurerAdapter<String, String> {
You can refer to the official documentation for more details.
Once this is active, you can inject the StateMachine as a dependency.

Spring Boot - the best way to read data from database on startup

I would like to read data to List or Map from database on startup.
Which is the best way to do it? The Spring Boot version is 5.
Is the below solution is good?
#Component
public class ApplicationStartup
implements ApplicationListener<ApplicationReadyEvent> {
/**
* This event is executed as late as conceivably possible to indicate that
* the application is ready to service requests.
*/
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
// here your code ...
return;
}
}
I'd like to storage data on static class, but I have doubt that is the best solution.
I don't quite understand what is your motive for doing so but for doing so you can create a bean using #Component and in that bean create a method with annotation #PostConstruct. you can do whatever you want in this method.
Using the ApplicationRunner interface is the best way to run code once the Spring boot context has loaded.
#Component
public class ApplicationStartup implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
}
}
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-command-line-runner

How do I register my custom Environment Post Processor in Spring Boot 2.0?

I followed the exact steps in this documentation.
I have the following entries in my META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor=com.mygroup.myapp.CustomEnvironmentPostProcessor
My post processor:
public class CustomEnvironmentPostProcessor
implements EnvironmentPostProcessor, Ordered {
..
}
I don't see anything in the logs as if it didn't get registered or not existing.
I unzipped the JAR and I can see META-INF/spring.factories. I can also see BOOT-INF/classes directly from the root.
What am I missing here?
There is no elegant way to solve this. You can make something like this :
#Component
public class CustomEnvironmentPostProcessor implements
EnvironmentPostProcessor, ApplicationListener<ApplicationEvent> {
private static final DeferredLog log = new DeferredLog();
#Override
public void postProcessEnvironment(
ConfigurableEnvironment env, SpringApplication app) {
log.error("This should be printed");
}
#Override
public void onApplicationEvent(ApplicationEvent event) {
log.replayTo(CustomEnvironmentPostProcessor.class);
}
}
define spring.factories file
Environment Post Processor
org.springframework.boot.env.EnvironmentPostProcessor=\
class name with package
As of Spring Boot 2.4, there are now optional constructor parameters that provide access to deferred logs:
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
private final Log log;
public CustomEnvironmentPostProcessor(Log log) {
this.log = log;
}
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
log.info("CustomEnvironmentPostProcessor!!");
}
}
NOTE: The log messages are deferred so they will appear in the log output only after the logging system has been initialized.
See https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/env/EnvironmentPostProcessor.html

Spring security - Access to a controller method based on an attribute

I'm configuring Spring Security across all my controllers.
I want some method executions to start only when "my system is enabled". This information is accessible from all over the controllers via a specific static method (I can make it non-static).
My point is that I want to avoid making an explicit check in java code at the beginning of every method.
How can I get there via Spring Security?
One approach is to use a handler interceptor.
Here is general idea:
(1) Configure url patterns which you want to block:
<util:list id="sysEnableCheckUrlPatterns" value-type="java.lang.String">
<beans:value>/module1/**</beans:value>
<beans:value>/module2/**</beans:value>
</util:list>
(2) Write an interceptor:
public class SysEnableCheckInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/*
If system enabled then return true. Otherwise return false (and optionally write something in response)
*/
}
}
(3) Configure that interceptor. In 3.1 you can do it as follows:
#Configuration
public class AppConfig extends WebMvcConfigurerAdapter {
#Resource(name="sysEnableCheckUrlPatterns")
/* or use #Autowired or #Inject if you like */
private String[] sysEnableCheckUrlPatterns;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new SysEnableCheckInterceptor()).addPathPatterns(sysEnableCheckUrlPatterns);
}
}
You can use SPEL (Spring Expression Language) in a security annotation.
See http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html

Resources