How to change a property value inside a Apache Camel Route? - groovy

In a property file a variable test has been defined:
test=OLD_VALUE
In the following Spring-DSL definition a camel route is defined. Properties are loaded via PropertiesComponent.
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="cache" value="false"/>
<property name="location" value="classpath:res.properties"/>
</bean>
<camelContext id="ctx" xmlns="http://camel.apache.org/schema/spring">
<route id="toParamRoute">
<from uri="servlet:myParam"/>
HERE I WOULD LIKE TO SET THE
VARIABLE TEST WITH A NEW VALUE,
SUCH THAT THE FOLLOWING LOG MESSAGE
WILL PRINT THE NEW VALUE,
E.G: test=NEW_VALUE
<log message="{{test}}"/>
</route>
</camelContext>
I tried different approach using groovy, language script expression, external spring bean but without success. Is there a way to set and change the value of a variable loaded at startup?
What is the best way to do it?
Anyone can help me? I did not find any similar question on stackoverflow! The problem I am facing and the solution I am looking for is a basic building-block to build a WEB UI management console to change some behavior of routes on the fly. To simplify the flow I can say that after propertyPlaceholder has loaded a property file then via a UI web page the default parameters of routes can be changed, and only after the route can be started.

Properties evaluated with syntax {{property}} are resolved only once during context initialization. If you need to reflect runtime changes, use Simple language
Example:
<bean id="myProperties" class="java.util.Properties"/>
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="cache" value="false"/>
<property name="location" value="classpath:res.properties"/>
<property name="overrideProperties" ref="myProperties" />
</bean>
<camelContext id="ctx" xmlns="http://camel.apache.org/schema/spring">
<route id="toParamRoute">
<from uri="timer://foo"/>
<log message="About to change property test from value ${properties:test} to value ${exchangeProperty.CamelTimerCounter}. Initial value was {{test}}"/>
<bean ref="myProperties" method="setProperty(test, ${exchangeProperty.CamelTimerCounter})" />
<log message="New value is ${properties:test}"/>
</route>
</camelContext>

Related

How can we make OOTB Component Attribute optional in Child component in SmartEdit?

Is there any way to make OOTB Component field optional in Child component in SmartEdit ?
For example, I extended CMSParagraphComponent by creating child component e.g. MyCustomParagraphComponent which extends CMSParagraphComponent.
OOTB CMSParagraphComponent -> content attribute is mandatory as defined in its CMS Structure API
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="CMSParagraphComponent" p:qualifier="content">
<property name="populators">
<set>
<ref bean="richTextComponentTypeAttributePopulator" />
<ref bean="requiredComponentTypeAttributePopulator" />
</set>
</property>
</bean>
requiredComponentTypeAttributePopulator makes this attribute mandatory. In addition, OOTB SmartEdit using cmsParagraphComponentValidator as well for backend validation.
Now I want to make content attribute optional for my custom MyCustomParagraphComponent
I tried creating new populator bean unRequiredComponentTypeAttributePopulator with required=false and assign it to content attribute of my custom component but that doesn’t work
Trying something like this ...
<bean id="unRequiredComponentTypeAttributePopulator" class="de.hybris.platform.cmsfacades.types.populator.RequiredComponentTypeAttributePopulator">
<property name="required" value="false" />
</bean>
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="PromotionalBannerComponent" p:qualifier="content">
<property name="populators">
<set>
<ref bean="unRequiredComponentTypeAttributePopulator" />
</set>
</property>
</bean>
But this is not working. It look like CMS Structure API works on only those attribute assigned directly to that component not parent one.
Then what is the correct way to do that ?
In your custom "facade-spring.xml", define the bean:
<bean id="optionalComponentTypeAttributePopulator" class="de.hybris.platform.cmsfacades.types.populator.RequiredComponentTypeAttributePopulator">
<property name="required" value="false" />
</bean>
Now, in your custom "facade-spring.xml", try overriding the bean of the Out of the Box:
<bean class="de.hybris.platform.cmsfacades.types.service.impl.DefaultComponentTypeAttributeStructure" p:typecode="CMSLinkComponent" p:qualifier="product">
<property name="populators">
<set>
<ref bean="optionalComponentTypeAttributePopulator" />
</set>
</property>
</bean>
I have tested this locally and it works perfectly.

Which way of specifiying my beans in spring-integration.xml is better?

I have two different ways of declaring a spring integration bean. They both seem to work. I'm using the Spring STS Eclipse based IDE.
This way:
<bean id="int-ftp:request-handler-advice-chain"
class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="trapException" value="true"></property>
<property name="onFailureExpression" value="#root"></property>
<property name="failureChannel" ref="errorChannel"></property>
</bean>
or this way:
<int-ftp:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice">
<property name="trapException" value="true" />
<property name="onFailureExpression" value="#root" />
<property name="failureChannel" ref="errorChannel" />
</bean>
</int-ftp:request-handler-advice-chain>
Which way is better?
For the target <int-ftp:outbound-gateway> it doesn't matter. Works well, as you noticed already.
Only the difference that the second declaration is nested and the final bean is visible only from the <int-ftp:request-handler-advice-chain> context.
The first definition is top-level global bean, which is visible everywhere and can be reused from other bean as well.
You can find more info about Inner Beans in the Spring Framework.

jpa inbound-channel-adapter doesn't support parameter source

I am trying to use the parameter-source to provide a parameter to my query in the inbound-channel-adapter but it doesn't seem to work. I have looked through the Parser code and I don't think it is processing the parameter-source.
<int-jpa:inbound-channel-adapter delete-after-poll="true"
delete-in-batch="true" auto-startup="true" flush-after-delete="true"
max-results="2000"
entity-manager-factory="entityManagerFactory"
entity-class="AuditMessage"
channel="processMessage"
jpa-query="select a from AuditMessage a where a.updateTs < :purgeDate"
parameter-source="parameterSource">
<int:poller cron="*/5 * * * * *" >
<int:transactional transaction-manager="transactionManager"/>
</int:poller>
</int-jpa:inbound-channel-adapter>
<bean id="parameterSource" factory-bean="spelSource"
factory-method="createParameterSourceNoCache">
<constructor-arg value="" />
</bean>
<bean id="spelSource"
class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<property name="parameterExpressions">
<map>
<entry key="purgeDate"
value="new java.sql.Timestamp(T(System).currentTimeMillis()-(T(java.util.concurrent.TimeUnit).MILLISECONDS.convert(${eam.integration.arcgis.purge.daysToKeep}, T(java.util.concurrent.TimeUnit).DAYS)))" />
</map>
</property>
</bean>
I get the following exception:
ERROR [task-scheduler-9] [java.lang.IllegalArgumentException: Query has parameters but no parameter source provided
at org.springframework.integration.jpa.core.DefaultJpaOperations.setParametersIfRequired(DefaultJpaOperations.java:330)
at org.springframework.integration.jpa.core.DefaultJpaOperations.getQuery(DefaultJpaOperations.java:114)
at org.springframework.integration.jpa.core.DefaultJpaOperations.getResultListForQuery(DefaultJpaOperations.java:186)
at org.springframework.integration.jpa.core.JpaExecutor.doPoll(JpaExecutor.java:396)...
I am on spring version 4.0.3. Am I doing something wrong? Or is there another way to provide query parameters?
I think you've just found a bug!
The JpaInboundChannelAdapterParser just doesn't parse the parameter-source attrbiute. Feel free to raise a JIRA bug.
As a workaround you must configure JpaPollingChannelAdapter as a raw <bean> with injection of JpaExecutor and use it as a ref from generic <int:inbound-channel-adapter>.
The JIRA ticket for those who would like to track.

Memory leak in Spring library : SimpleMessageStore

3 of the webservices that I am working on uses Springs, SimpleMessageStore for storing the messages. For some reason it is causing memory leak in production env and I am unable to reproduce it in the lower environments. I am new to spring integration and need help in understanding what might be causing this.
the spring config code looks like this:
<!-- MESSAGE STORES -->
<bean id="monitoringHeaderRequestMsgStore" class="org.springframework.integration.store.SimpleMessageStore"/>
<bean id="gbqHeaderRequestMsgStore" class="org.springframework.integration.store.SimpleMessageStore"/>
<bean id="bondAgreementResponseMsgStore" class="org.springframework.integration.store.SimpleMessageStore"/>
<bean id="bondWIthRulesRequestMsgStore" class="org.springframework.integration.store.SimpleMessageStore"/>
<bean id="ProcessVariableMessageStores" class="com.aviva.uklife.investment.impl.ProcessVariableMessageStores">
<property name="_monitoringHeaderRequestMsgStore" ref="monitoringHeaderRequestMsgStore"/>
<property name="_gbqHeaderRequestMsgStore" ref="gbqHeaderRequestMsgStore"/>
<property name="_bondWIthRulesRequestMsgStore" ref="bondWIthRulesRequestMsgStore"/>
<property name="_bondAgreementResponseMsgStore" ref="bondAgreementResponseMsgStore"/>
</bean>
<!-- Retrieve stored MonitoringHeaderRequest -->
<int:transformer expression="headers.get('#{T(.....Constants).MONITORING_HEADER_REQUEST_CLAIM_CHECK_ID}')"/>
<int:claim-check-out message-store="monitoringHeaderRequestMsgStore" remove-message="false"/>
<!-- Store HeaderRequest -->
<int:gateway request-channel="header-req-store-channel"/>
<!-- PROCESS VARIABLES STORAGE IN STORE CHANNELS WITH KEY OR CLAIMCHECK ID -->
<int:chain input-channel="monitoring-header-req-store-channel">
<int:claim-check-in message-store="monitoringHeaderRequestMsgStore"/>
<int:header-enricher>
<int:header name="#{T(....Constants).MONITORING_HEADER_REQUEST_CLAIM_CHECK_ID}" expression="payload"/>
</int:header-enricher>
<int:claim-check-out message-store="monitoringHeaderRequestMsgStore" remove-message="false"/>
</int:chain>
thank you
To be honest, it isn't recommended to use SimpleMessageStore in the production environment. That's because of memory-leak, as you noticed. If you don't clear the MessageStore periodically.
Right, there are might be some cases, when you need to keep messages in the MessageStore for the long time. So consider to replace SimpleMessageStore with some persistent MessageStore.
From other side we need to have more info on the matter to provide better help.
Maybe you just have several aggregators and don't use expire-groups-upon-completion = "true"...

Spring MVC 3 content negotiation restrict to actions which support it

I have configured content negotiation in my Spring MVC 3 app as follows:
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="0" />
<property name="favorPathExtension" value="true" />
<property name="defaultContentType">
<ref bean="htmlMediaType" />
</property>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.castor.CastorMarshaller" />
</property>
</bean>
</list>
</property>
<property name="viewResolvers">
<ref bean="tilesViewResolver" />
</property>
</bean>
This works very well -- all my views will render as html views with the 'normal' view templates, or as JSON or XML dumps of the view model data depending on the 'Accept' header.
However, this seems to be a bit of a security hole to me. Some of my actions are API-style actions, and are legitimately available in HTML or JSON or XML. However, some views are intended to be HTML-only. I don't really want end-users to be able to see all the view data just by adding ".json" to the url.
Is there any way to do content negotiation in Spring MVC, but only on actions which have explicitly opted-in to it? Can I set up a controller annotation like #RespondsTo("xml", "json")?
Why don't you use a filter through DelegatingFilterProxy to block users from accessing unnecessary content types ?
I was just facing the same problem. produces attribute of #RequestMapping helps for that. Although it's the opposite of what you asked for - kind of opt-out instead of opt-in, but I think it's what can please you.
#Controller
#RequestMapping("/categories")
public class CategoriesController
{
#RequestMapping(value = "/create", method = RequestMethod.GET, produces = "application/xhtml+xml")
public String createForm(Model model)
{
}
}
/create - works fine by displaying JSP view
/create.json - 406 Error
One way to do it would be to use Spring Security to restrict which pages can be seen based on the content-type (or whatever other method(s) you are using for content negotiation.

Resources