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.
Related
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.
I have a http gateway call that's occasionally returning 503 errors. I'd like to configure retry advice around that call, but I don't want to do it for every error, just the 503s.
<int-http:outbound-gateway ... errorHandler="...">
<int-http:request-handler-advice-chain>
<int:retry-advice max-attempts="3" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
I already have a custom error handler configured that filters statuses (ex: 404) that I don't want to treat as errors, but I don't see an obvious way to control how the advice is applied based on what I can do in the error handler. This question deals with the same issue, but the answer doesn't explain how to control the advice behavior or reissue the request at the error handler level. Is there a specific exception type to throw?
edit: Example based on answer:
<bean id="spelParser" class="org.springframework.expression.spel.standard.SpelExpressionParser" />
<int-http:outbound-gateway ...>
<int-http:request-handler-advice-chain>
<bean class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.ExpressionRetryPolicy">
<constructor-arg index="0" type="org.springframework.expression.Expression" value="#{spelParser.parseExpression('cause.statusCode.value() == 503')}" />
<property name="maxAttempts" value="3" />
</bean>
</property>
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="1000" />
<property name="multiplier" value="2" />
</bean>
</property>
</bean>
</property>
</bean>
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
Well, for the case when you have a HttpServerErrorException but would like to distinguish it by the statusCode from others and don't retry, I would suggest to take a look into the:
* Subclass of {#link SimpleRetryPolicy} that delegates to super.canRetry() and,
* if true, further evaluates an expression against the last thrown exception.
*
* #author Gary Russell
* #since 1.2
*
*/
#SuppressWarnings("serial")
public class ExpressionRetryPolicy extends SimpleRetryPolicy implements BeanFactoryAware {
Where your expression can be like:
expression="statusCode.value() == 503"
UPDATE
Ah! I see. Since ExpressionRetryPolicy uses TemplateParserContext your expression definitely must be like #{statusCode.value() == 503}. But at the same time it is going to be evaluate during bean factory initialization. I suggest you to do something like this:
<bean id="spelParser" class="org.springframework.expression.spel.standard.SpelExpressionParser"/>
and in the ExpressionRetryPolicy bean definition do:
<constructor-arg index="0" type="org.springframework.expression.Expression"
value="#{spelParser.parseExpression('statusCode.value() == 503')}" />
To overcome the collision.
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.
I am using Spring Batch 3.2 for bulk migration of data from XML to Database.
My XML contains around 140K users and I want to dump it into DB.
I do not want to proceed it in a single thread.
I tried using TaskExecutor but not able to succeed due to below error.
at java.lang.Thread.run(Thread.java:724)
Caused by: com.ctc.wstx.exc.WstxParsingException: Unexpected close tag </consumerName>; expected </first>.
at [row,col {unknown-source}]: [4814,26]
at com.ctc.wstx.sr.StreamScanner.constructWfcException(StreamScanner.java:606)
at com.ctc.wstx.sr.StreamScanner.throwParseError(StreamScanner.java:479)
at com.ctc.wstx.sr.StreamScanner.throwParseError(StreamScanner.java:464)
at com.ctc.wstx.sr.BasicStreamReader.reportWrongEndElem(BasicStreamReader.java:3283)
at com.ctc.wstx.sr.BasicStreamReader.readEndElem(BasicStreamReader.java:3210)
at com.ctc.wstx.sr.BasicStreamReader.nextFromTree(BasicStreamReader.java:2829)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1072)
at org.codehaus.stax2.ri.Stax2EventReaderImpl.peek(Stax2EventReaderImpl.java:367)
at org.springframework.batch.item.xml.stax.DefaultFragmentEventReader.nextEvent(DefaultFragmentEventReader.java:114)
at org.springframework.batch.item.xml.stax.DefaultFragmentEventReader.markFragmentProcessed(DefaultFragmentEventReader.java:184)
where consumerName and first are XML nodes.
I knew StaxEventItemReader is not a thread safe and multiple threads are using XML and due to that issue, there is some problem in marking fragments as processed and I am not able to get unique record as well as complete fragment to process.
Can any one suggest me how Can I use multi-threading/partitioning in my case.
What I want
By using multi-threading, how can I make sure that each thread get unique chuck i.e (Thread 1 - fragement 1-100, Thread 2 - fragement 101-200.... so on)
Each thread process unique chuck and dump into DB.
My configuration
<batch:job id="sampleJob">
<batch:step id="multiThreadStep" allow-start-if-complete="true">
<batch:tasklet transaction-manager="transactionManager" task-executor="taskExecutor" throttle-limit="10">
<batch:chunk reader="xmlItemReader" writer="itemWriter"
processor="itemProcessor" commit-interval="10" skip-limit="1500000">
<batch:skippable-exception-classes>
<batch:include class="java.lang.Exception" />
</batch:skippable-exception-classes>
</batch:chunk>
</batch:tasklet>
</batch:step>
</batch:job>
<!-- <bean id="taskExecutor" class="org.springframework.core.task.SimpleAsyncTaskExecutor">
<property name="concurrencyLimit" value="10"/>
</bean> -->
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="10" />
<property name="allowCoreThreadTimeOut" value="true" />
</bean>
<bean id="xmlItemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="userItem" />
<property name="unmarshaller" ref="userDetailUnmarshaller" />
<property name="saveState" value="false" />
</bean>
Sample XML
<userItems>
<userItem>
<...>
<...>
</userItem>
<userItem>
<...>
<...>
</userItem>
...
...
</userItems>
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.