Thymeleaf - check if a template exists - spring-boot

I am searching a way to check if a template exists before returning it in a view with Thymeleaf and Spring.
In my controller i was trying to do something like this:
String finalTemplate = template.getPrefix() + "/" + templateName;
try {
return finalTemplate;
} catch(TemplateInputException e) {
logger.debug("Sono qua");
return templateName;
}
but the exception is not catch...

The way you are handling exception here will not work for template exceptions.
Check below threads regarding this in issues section github.
https://github.com/thymeleaf/thymeleaf-spring/issues/94
https://github.com/thymeleaf/thymeleaf-spring/issues/81

StringTemplateResource from the comment above seems to return true in every case for thymeleaf 3.0. Here is a method to do this for classpath included templates:
public static String baseDir = "templates";
/**
* Check if a template exists in subfolder templates.
*
* #param templateName relative name of template below the basedir.
* #return true if exists, otherwise false
*/
public static boolean templateExists(final String templateName)
{
final ClassLoaderTemplateResource iTemplateResource =
new ClassLoaderTemplateResource(baseDir + "/" + templateName, "UTF8");
return iTemplateResource.exists();
}
Testcase:
#Test
public void testNonExisting()
{
assertFalse(templateExists("foo"));
}
#Test
public void testExisting()
{
assertTrue(templateExists("foo.txt"));
}
Assuming a classpath resource templates/foo.txt exists.

Related

//NonCompliant comment usage - SonarQube Custom Rule

I am trying to write a few SONARQUBE custom rules for my project.
After reading up the below document -
https://docs.sonarqube.org/display/PLUG/Writing+Custom+Java+Rules+101
and
https://github.com/SonarSource/sonar-custom-rules-examples,
I created a custom rule like these classes below -
The Rule file:
#Rule(key = "MyAssertionRule")
public class FirstSonarCustomRule extends BaseTreeVisitor implements JavaFileScanner {
private static final String DEFAULT_VALUE = "Inject";
private JavaFileScannerContext context;
/**
* Name of the annotation to avoid. Value can be set by users in Quality
* profiles. The key
*/
#RuleProperty(defaultValue = DEFAULT_VALUE, description = "Name of the annotation to avoid, without the prefix #, for instance 'Override'")
protected String name;
#Override
public void scanFile(JavaFileScannerContext context) {
this.context = context;
System.out.println(PrinterVisitor.print(context.getTree()));
scan(context.getTree());
}
#Override
public void visitMethod(MethodTree tree) {
List<StatementTree> statements = tree.block().body();
for (StatementTree statement : statements) {
System.out.println("KIND IS " + statement.kind());
if (statement.is(Kind.EXPRESSION_STATEMENT)) {
if (statement.firstToken().text().equals("Assert")) {
System.out.println("ERROR");
}
}
}
}
}
The Test class:
public class FirstSonarCustomRuleTest {
#Test
public void verify() {
FirstSonarCustomRule f = new FirstSonarCustomRule();
f.name = "ASSERTION";
JavaCheckVerifier.verify("src/test/files/FirstSonarCustom.java", f);
}
}
And finally - the Test file:
class FirstSonarCustom {
int aField;
public void methodToUseTestNgAssertions() {
Assert.assertTrue(true);
}
}
The above Test file would later be my Project's source code.
As per the SONAR documentation - the // Noncompliant is a mandatory comment in my Test file. Thus my first question is should I add this comment everywhere in my Source code too?
If yes - is there any way I can avoid adding this comment, because I do not want to add that code refactoring exercise all over.
Can someone suggest me what I need to do here?
I am using SONARQUBE 6.3.
This comment is only used by the test framework (JavaCheckVerifier class) to test the implementation of your rule. It is not mandatory in any way and for sure you don't need it in your real code.

spring replace class ExpressionEvaluationUtils

I have the following code and I migrated my project from spring 3 to spring 4.
But ExpressionEvaluationUtils is obsolete actually.
Do you have any idea to replace it ?
/**
* Set quote escaping for this tag, as boolean value. Default is "true".
*/
public void setQuoteEscape(String quoteEscape) throws JspException {
this.quoteEscape = ExpressionEvaluationUtils.evaluateBoolean("quoteEscape", quoteEscape, pageContext);
}
/**
* Set breakLine escaping for this tag, as boolean value. Default is "true".
*/
public void setBackslashEscape(String backslashEscape) throws JspException {
this.backslashEscape = ExpressionEvaluationUtils.evaluateBoolean("backslashEscape", backslashEscape, pageContext);
}
Do you have any idea to replace it?

Spring Boot: Override convention used to find application.properties config files

I was looking at the spring-boot documentation located here
Specifically the section regarding the order in which the properties are considered:
More specifically:
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
Let me first mention that I am not having any issues loading profile specific configurations using this approach(provided that the files are located in classpath:/ or classpath:/config.
However, what I am hoping to do is implement a convention like the following:
classpath:/default/application.properties
classpath:/{profile}/application.properties
Furthermore I'd like to achieve this configuration without making use of the spring.config.location property. I'm pretty new to Spring Boot so I'm looking for some hints as how to how I would implement this convention. Based on my research It seems that this might be achievable by adding a custom ConfigFileApplicationListener. Please let me know if that is a sensible starting point or any other ideas that might be better.
Update:
It seems that if I could programmatically build out the spring.config.location list of properties I could pass in locations such as classpath:/default, classpath:{profile}. based on the spring.profiles.active environment variable. The following ConfigFileApplicationListener seems like its the one I want to call:
public void setSearchLocations(String locations)
However, I'm not sure where in the lifecycle I would make such a call.
So here is what I managed to come up with, not sure if I'll even go with this solution but I figured I'll offer it up in case there is any helpful feedback.
So I resorted to trying to set the call the setSearchLocations(String locations) method on the ConfigFileApplicationListener after it has been added to the SpringApplication but before its triggered. I did this by adding a new listener that also implements Ordered and made sure it ran before ConfigFileApplicationListener. This seems to do what I want but I'm still thinking there is a more elegant approach. I especially dont like having to iterate over the Listeners.
public class LocationsSettingConfigFileApplicationListener implements
ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
/**
* this should run before ConfigFileApplicationListener so it can set its
* state accordingly
*/
#Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
}
#Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
SpringApplication app = event.getSpringApplication();
ConfigurableEnvironment env = event.getEnvironment();
for (ApplicationListener<?> listener : app.getListeners()) {
if (listener instanceof ConfigFileApplicationListener) {
ConfigFileApplicationListener cfal = (ConfigFileApplicationListener) listener;
//getSearchLocations omitted
cfal.setSearchLocations(getSearchLocations(env));
}
}
}
A solution that doesn't require writing a new class:
public static void main(String[] args) {
SpringApplication app = new SpringApplication();
app.getListeners().stream()
.filter(listener -> listener instanceof ConfigFileApplicationListener)
.forEach(configListener -> {
((ConfigFileApplicationListener) configListener).setSearchLocations(mySearchLocations);
((ConfigFileApplicationListener) configListener).setSearchNames(mySearchNames);
});
app.setSources(singleton(MyClassName.class));
app.run(args);
}
We did something similar with an EnvironmentPostProcessor to achieve the following naming convention:
System properties
environment variables
"random" (not used, but we kept that default PropertySource)
file:${foo.home}/foo-<profile>.properties
classpath*:<appName-profile>.properties
classpath*:application-profile.properties
classpath*:<appName>.properties
classpath*:application.properties
classpath*:meta.properties
Some applications do not have their own <appName>; those that do call setApplicationName in the main class's static initializer to use those two additional files.
The hacky part here is that we do not exclude the default ConfigFileApplicationListener, but undo it by removing PropertySource ConfigFileApplicationListener.APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME.
File FooPropertiesEnvPostProcessor.java
package example.foo.utils.spring;
import static org.springframework.core.env.AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME;
import java.io.IOException;
import java.util.List;
import java.util.Spliterators;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.PropertySourcesLoader;
import org.springframework.boot.logging.LoggingApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* Configures environment properties according to the FOO conventions.
*/
public class FooPropertiesEnvPostProcessor implements EnvironmentPostProcessor, Ordered {
/**
* Order before LoggingApplicationListener and before
* AutowiredAnnotationBeanPostProcessor. The position relative to
* ConfigFileApplicationListener (which we want to override) should not
* matter: If it runs before this, we remove its PropertySource; otherwise,
* its PropertySource remains but should do no harm as it is added at the
* end.
*/
public static final int ORDER
= Math.min(LoggingApplicationListener.DEFAULT_ORDER, new AutowiredAnnotationBeanPostProcessor().getOrder()) - 1;
static {
System.setProperty(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME,
System.getProperty(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, "production"));
}
public FooPropertiesEnvPostProcessor() {
}
/**
* Property key used as the application (sub-project) specific part in
* properties file names.
* <p>
* <strong>Note:</strong> Direct access to this property key is meant for
* tests which set the property in an annotation (e.g.
* {#link IntegrationTest}). However, SpringBootApplications which need to
* set this system property before Spring initialization should call
* {#link #setApplicationName(String) setApplicationName} instead.
* </p>
*/
public static final String APP_KEY = "foo.config.name";
/**
* Sets the application name used to find property files (using
* {#link FooPropertiesEnvPostProcessor}).
*
* #param appName
* the application name
*/
public static void setApplicationName(String appName) {
System.setProperty(APP_KEY, appName);
}
/**
* Replacement for logging, which is not yet initialized during
* postProcessEnvironment.
*/
static void log(String format, Object... args) {
System.out.println(String.format(format, args));
}
static void debug(PropertyResolver env, String format, Object... args) {
String level = env.getProperty("logging.level." + FooPropertiesEnvPostProcessor.class.getName());
if ("trace".equalsIgnoreCase(level) || "debug".equalsIgnoreCase(level)) {
log(format, args);
}
}
static void trace(PropertyResolver env, String format, Object... args) {
String level = env.getProperty("logging.level." + FooPropertiesEnvPostProcessor.class.getName());
if ("trace".equalsIgnoreCase(level)) {
log(format, args);
}
}
#Override
public int getOrder() {
return ORDER;
}
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
addProperties(environment.getPropertySources(), application.getResourceLoader(), environment);
}
public static void addProperties(MutablePropertySources propSources, ResourceLoader resLoader, ConfigurableEnvironment propRes) {
trace(propRes, "FooPropertiesEnvPostProcessor.addProperties(..)");
List<PropertySourceLoader> psls = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
PropertySourcesLoader.class.getClassLoader());
// ResourcePatternUtils does not accept null yet
// (https://jira.spring.io/browse/SPR-14500)
ResourcePatternResolver rpr = resLoader != null ? ResourcePatternUtils.getResourcePatternResolver(resLoader)
: new PathMatchingResourcePatternResolver();
final String suffix = ".properties"; // SonarQube made me declare this
String[] profiles = propRes.getActiveProfiles();
if (profiles.length == 0) {
profiles = new String[] { System.getProperty(DEFAULT_PROFILES_PROPERTY_NAME) };
}
// ConfigFileApplicationListener adds PropertySource "applicationConfigurationProperties" consisting of
// - "applicationConfig: [classpath:/${spring.config.name}-<profile>.properties]"
// - "applicationConfig: [classpath:/${spring.config.name}.properties]"
// Since we want the profile to have higher priority than the app name, we cannot just set
// "spring.config.name" to the app name, use ConfigFileApplicationListener, and add
// "application-<profile>.properties" and "application.properties".
// Instead, remove ConfigFileApplicationListener:
PropertySource<?> removedPropSource = propSources.remove(ConfigFileApplicationListener.APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME);
trace(propRes, "removed %s from %s", removedPropSource, propSources);
// add meta.properties at last position, then others before the previously added. => resulting order:
// - { systemProperties
// - systemEnvironment
// - random } - already added automatically elsewhere
// - file:${foo.home}/foo-<profile>.properties
// - classpath:<appName>-<profile>.properties
// - classpath:application-<profile>.properties
// - classpath:<appName>.properties
// - classpath:application.properties
// - classpath:meta.properties
// By adding ${foo.home}/... (chronlogically) last, the property can be set in the previously added resources.
boolean defaultAppName = "application".equals(propRes.resolveRequiredPlaceholders("${" + APP_KEY + ":application}"));
String psn = null;
psn = addProperties(propSources, propRes, rpr, psls, true, psn, propRes.resolveRequiredPlaceholders("classpath*:meta" + suffix));
psn = addProperties(propSources, propRes, rpr, psls, true, psn, propRes.resolveRequiredPlaceholders("classpath*:application" + suffix));
if (!defaultAppName) {
psn = addProperties(propSources, propRes, rpr, psls, false,
psn, propRes.resolveRequiredPlaceholders("classpath*:${" + APP_KEY + ":application}" + suffix));
}
for (String profile : profiles) {
psn = addProperties(propSources, propRes, rpr, psls, false, psn,
propRes.resolveRequiredPlaceholders("classpath*:application-" + profile + suffix));
}
if (!defaultAppName) {
for (String profile : profiles) {
psn = addProperties(propSources, propRes, rpr, psls, false,
psn, propRes.resolveRequiredPlaceholders("classpath*:${" + APP_KEY + ":application}-" + profile + suffix));
}
}
for (String profile : profiles) {
psn = addProperties(propSources, propRes, rpr, psls, false,
psn, propRes.resolveRequiredPlaceholders("file:${foo.home:.}/foo-" + profile + suffix));
}
Stream<PropertySource<?>> propSourcesStream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(propSources.iterator(), 0), false);
debug(propRes, "Property sources: %s%n", propSourcesStream.map(PropertySource::getName).collect(Collectors.joining(", ")));
}
/**
* Adds a resource given by location string to the given PropertySources, if
* it exists.
*
* #param propSources
* the property sources to modify
* #param successorName
* the name of the (already added) successor resource, i.e. the
* resource before which the new one should be added; if null,
* add as last resource
* #param location
* the location of the resource to add
* #return the name of the newly added resource, or {#code successorName} if
* not added
*/
private static String addProperties(MutablePropertySources propSources, PropertyResolver propRes, ResourcePatternResolver resLoader,
List<PropertySourceLoader> propLoaders, boolean required, String successorName, String location) {
Resource[] resources;
try {
resources = resLoader.getResources(location);
} catch (IOException e) {
throw new IllegalStateException("failed to load property source " + location + ": " + e, e);
}
if (resources.length == 0) {
debug(propRes, "%s property resource not found: %s", required ? "required" : "optional", location);
if (required) {
throw new IllegalStateException("required property source " + location + " not found");
} else {
return successorName;
}
}
String newSuccessorName = successorName;
for (Resource resource : resources) {
boolean exists = resource.exists();
debug(propRes, "%s property resource %sfound: %s%s", required ? "required" : "optional", exists ? "" : "not ", location,
uriDescription(resource, propRes));
if (!required && !exists) {
continue;
}
boolean loaded = false;
for (PropertySourceLoader propLoader : propLoaders) {
if (canLoadFileExtension(propLoader, resource)) {
newSuccessorName = addResource(propSources, propRes, resource, propLoader, newSuccessorName);
loaded = true;
break;
}
}
if (!loaded && required) {
throw new IllegalStateException("No PropertySourceLoader found to load " + resource);
}
}
return newSuccessorName;
}
private static String addResource(MutablePropertySources propSources, PropertyResolver propRes, Resource resource,
PropertySourceLoader propLoader, String successorName) {
try {
PropertySource<?> propSource = propLoader.load(resource.getDescription(), resource, null);
if (propSource == null) {
// e.g. a properties file with everything commented;
// org.springframework.boot.env.PropertiesPropertySourceLoader
// converts empty to null
return successorName;
}
if (successorName == null) {
propSources.addLast(propSource);
} else if (successorName.equals(propSource.getName())) {
// happens if APP_KEY is not set, so that
// "${APP_KEY:application}" == "application"
trace(propRes, "skipping duplicate resource %s", successorName);
} else {
propSources.addBefore(successorName, propSource);
}
return propSource.getName();
} catch (IOException e) {
throw new IllegalStateException("Unable to load configuration file " + resource + ": " + e, e);
}
}
/**
* Stolen from {#link PropertySourcesLoader}
*/
private static boolean canLoadFileExtension(PropertySourceLoader loader, Resource resource) {
String filename = resource.getFilename().toLowerCase();
for (String extension : loader.getFileExtensions()) {
if (filename.endsWith("." + extension.toLowerCase())) {
return true;
}
}
return false;
}
private static String uriDescription(Resource resource, PropertyResolver propRes) {
try {
return resource.exists() ? (" in " + resource.getURI()) : "";
} catch (IOException e) {
trace(propRes, "getURI: %s", e);
return "";
}
}
}
File META-INF/spring.factories
org.springframework.boot.env.EnvironmentPostProcessor = example.foo.utils.spring.FooPropertiesEnvPostProcessor
To get the same properties in tests, they have #ContextConfiguration(..., initializers = TestAppContextInitializer.class).
TestAppContextInitializer implements ApplicationContextInitializer<GenericApplicationContext> and calls
FooPropertiesEnvPostProcessor.addProperties in its initialize method.
Unfortunately, the EnvironmentPostProcessor seems to be missing Spring Shell by default, too. In our case (since only a tiny
part of the application uses Spring Shell), it was sufficient to restrict the <context:component-scan base-package=.../>
scope in META-INF/spring/spring-shell-plugin.xml to contain only stuff which does not need any properties set by the EnvironmentPostProcessor.
# override from outer config , eg. java -jar --spring.profiles.active=your config
spring.profiles.active=dev
spring.config.location=classpath:/${spring.profiles.active}/application.properties

Externalized message.properties file is not picking up in Tomcat

According to my requirement, I need to externalize the message.properties file (Keep outside from war file) and in same time it should be automatically re loadable on update.
So I achieved both by following code and its working fine with Jetty Server. But in when I use Tomcat Server that externalized property file is not picking up by the system, instead its uses only the file inside the war.
public final class Messages
{
public static final String BUNDLE_NAME = "com.sample.project.core.ui.resources.messages";
// private static ResourceBundle resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME);
private static ResourceBundle resourceBundle;
private static final Logger LOGGER = Logger.getLogger(Messages.class);
private static ReloadableResourceBundleMessageSource messageSource;
static
{
try
{
FileInputStream fis =
new FileInputStream(System.getProperty("resources.messages.file.path"));
resourceBundle = new PropertyResourceBundle(fis);
}
catch (FileNotFoundException e)
{
LOGGER.error("messages.properties file not found: " + e);
resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME);
}
catch (Exception e)
{
LOGGER.error("messages.properties file reading failed: " + e);
resourceBundle = ResourceBundle.getBundle(BUNDLE_NAME);
}
}
private Messages()
{
}
/**
* <p>
* setter methos to ReloadableResourceBundleMessageSource object.
* </p>
*
*
* #param inMessageSource
* set reloadable resources bundle
**/
public static void setMessageSource(final ReloadableResourceBundleMessageSource inMessageSource)
{
Messages.messageSource = inMessageSource;
Messages.messageSource.setBasename(System.getProperty("resources.messages.file.path"));
}
/**
* <p>
* Resolve a message by a key and argument replacements.
* </p>
*
* #see MessageFormat#format(String, Object...)
* #param key
* the message to look up
* #param arguments
* optional message arguments
* #return the resolved message
**/
public static String getMessage(final String key, final Object... arguments)
{
try
{
if (messageSource != null)
{
return messageSource.getMessage(key, arguments, Locale.getDefault());
}
else
{
if (arguments != null)
return MessageFormat.format(resourceBundle.getString(key), arguments);
return resourceBundle.getString(key);
}
}
catch (NoSuchMessageException e)
{
LOGGER.error("Message key not found: " + key);
return '!' + key + '!';
}
catch (MissingResourceException e)
{
LOGGER.error("Message key not found: " + key);
return '!' + key + '!';
}
}
}
(Here file path I'm passing as a VM argument using "resources.messages.file.path" key)
First I thought it was a problem with accessing the file system and tried many ways. Then I heard about catalina.policy file and I added some lines like this..
grant codeBase "file:${catalina.base}/webapps/sample.war/-" {
permission java.security.AllPermission;
permission java.io.FilePermission "file:${catalina.base}${file.separator}webapps${file.separator}messages.properties", "read, write";
permission java.util.PropertyPermission "resources.messages.file.path", "read";
}
But non of them gave me luck. I'm desperate. Any idea what this issue is? Please help me. Thank you in advance. (Tested on Tomcat6)
Finally I found where I screwed up.
This setter method of messageSource should not be static and I removed static access of messageSource
messageSource = inMessageSource;
messageSource.setBasename(System.getProperty("resources.messages.file.path"));
Now code is working fine. And no need of that permission entry in catalina.policy file. Thanks to everyone who helped me.

Add camel route at runtime in Java

How can I add a camel route at run-time in Java? I have found a Grails example but I have implement it in Java.
My applicationContext.xml already has some predefined static routes and I want to add some dynamic routes to it at run time.
Is it possible?
Because the only way to include dynamic route is to write the route.xml and then load the route definition to context. How will it work on existing static routes?
Route at runtime
you can simply call a few different APIs on the CamelContext to add routes...something like this
context.addRoutes(new MyDynamcRouteBuilder(context, "direct:foo", "mock:foo"));
....
private static final class MyDynamcRouteBuilder extends RouteBuilder {
private final String from;
private final String to;
private MyDynamcRouteBuilder(CamelContext context, String from, String to) {
super(context);
this.from = from;
this.to = to;
}
#Override
public void configure() throws Exception {
from(from).to(to);
}
}
see this unit test for the complete example...
https://svn.apache.org/repos/asf/camel/trunk/camel-core/src/test/java/org/apache/camel/builder/AddRoutesAtRuntimeTest.java
#Himanshu,
Please take a look at dynamicroute options (in other words routing slip) that may help you dynamically route to different 'destinations' based on certain condition.
Check the dynamic router help link in camel site;
http://camel.apache.org/dynamic-router.html
from("direct:start")
// use a bean as the dynamic router
.dynamicRouter(method(DynamicRouterTest.class, "slip"));
And within the slip method;
/**
* Use this method to compute dynamic where we should route next.
*
* #param body the message body
* #return endpoints to go, or <tt>null</tt> to indicate the end
*/
public String slip(String body) {
bodies.add(body);
invoked++;
if (invoked == 1) {
return "mock:a";
} else if (invoked == 2) {
return "mock:b,mock:c";
} else if (invoked == 3) {
return "direct:foo";
} else if (invoked == 4) {
return "mock:result";
}
// no more so return null
return null;
}
Hope it helps...
Thanks.
One such solution could be:
Define route:
private RouteDefinition buildRouteDefinition() {
RouteDefinition routeDefinition = new RouteDefinition();
routeDefinition.from(XX).to(ZZ); // define any route you want
return routeDefinition;
}
Get Model Context and create route:
CamelContext context = getContext();
ModelCamelContext modelContext = context.adapt(ModelCamelContext.class);
modelContext.addRouteDefinition(routeDefinition);
There are more way of getting camel context. To name few:
In processor, you can use exchange.getContext()
Through RouteBuilder reference, you can use routeBuilder.getContext()

Resources