Using custom registries within apache camel - java

Apache Camel does not seem to support any bean that is to be used within its registry. I am currently trying to add an AWS S3 Client object/bean to the spring configuration without any luck. The bean itself is added to the registry, but when camel goes to use the client object it throws an error similar to this:
Caused by: java.lang.IllegalArgumentException: Could not find a
suitable setter for property: amazonS3Client as there isn't a setter method
with same type: java.lang.String nor type conversion possible: No type
converter available to convert from type: java.lang.String to the
required type: com.amazonaws.services.s3.AmazonS3 with value
#amazonClient
The amazonClient is the aforementioned bean that is added appropriately the spring config which has led me to believe the camel config is indeed finding the bean. Here is the related xml configuration:
<!-- set up default amazon s3 client from amazon aws sdk -->
<bean id="amazonClient" class="com.amazonaws.services.s3.AmazonS3Client">
<constructor-arg>
<bean class="com.amazonaws.auth.BasicAWSCredentials">
<constructor-arg name="accessKey" value=""/>
<constructor-arg name="secretKey" value=""/>
</bean>
</constructor-arg>
</bean>
Within the camel context section (you can see the bean is mentioned):
<camel:route id="importFilesFromS3">
<camel:from uri="aws-s3://intuit-commerce-imports?amazonS3Client=#amazonClient&region=us-west-2&deleteAfterRead=true"/>
<camel:to uri="ref:importProcessingEndpoint"/>
</camel:route>
Apache camel claims to have this feature in their documentation, but I have found a few sources that come across the same issue. The answer in the link does not provide much explanation.

I've never worked with AWS S3, but I also ran into a similar problem with Camel seemingly not able to find the bean within the Spring registry.
By stepping through IntrospectionSupport.setProperty, I noticed that CamelContextHelper.lookup was using JndiRegistry instead of the ApplicationContextRegistry.
My solution was to add camel-spring as a project dependency, as well as to initialize my camel context with ApplicationContextRegistry:
camelContext = new DefaultCamelContext(new ApplicationContextRegistry(applicationContext));

Related

Unable to register MBean for ws-outbound-gateway

The integration flow uses the following:
<int:chain input-channel="input" id="inChain">
<!-- some header-enrichers -->
<int-ws:outbound-gateway id="outGateway"/> <!-- other properties are omitted -->
</int:chain>
In the process of deploying to Tomcat, i get an error:
Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException:
Unable to register MBean [inChain$child.outGateway.handler] with key 'inChain$child.outGateway.handler';
nested exception is org.springframework.jmx.export.MBeanExportException:
Could not create ModelMBean for managed resource [inChain$child.outGateway.handler] with key 'inChain$child.outGateway.handler';
nested exception is java.lang.IllegalArgumentException:
MetadataMBeanInfoAssembler does not support JDK dynamic proxies - export the target beans directly or use CGLIB proxies instead.
Is there a simple solution in spring integration or is it necessary to follow the advice from the error text (make a custom MBeanExporter and so on)?
May be better to think not making that gateway as a proxy at all? How that happen though? Nothing confirms in your question that there is a story about proxying... on the other hand you can exclude that bean from JMX exporting. Or you can provide an other way to gather MBean info for that bean. See how you can customize MBeanExporter.
Or you just can add an IntegrationMBeanExporter: https://docs.spring.io/spring-integration/docs/current/reference/html/jmx.html#jmx-mbean-exporter
Thanks to Artem Bilan for search direction: found AOP advice in code:
<bean id="interceptor" class="..."/>
<aop:config>
<aop:pointcut id="all" expression="execution(*org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleRequestMessage(..))"/>
<aop:advisor pointcut-ref="all" advice-ref="interceptor" order="1"/>
</aop:config>
The best solution for now is to disable JMX.

Marklogic XCC ContentSource using JNDI

I'm trying to get a Marklogic ContentSource object loaded from Tomcat's context.xml using JNDI and Spring.
I'm using Tomcat 8.5, and Spring 2.5 (unfortunately)
I have added the following to context.xml in Tomcat
<Resource name="MLContentSource" auth="Container" type="com.marklogic.xcc.ContentSource"
factory="com.marklogic.xcc.jndi.ContentSourceBeanFactory"
url="xcc://username:password#mymarklogic-server/DatabaseName"/>
And the following in my applicationContext.xml
<bean id="contentSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/MLContentSource"/>
</bean>
I have another bean declared in my applicationContext.xml that relies on the ContentSource bean. Its expecting a property to be set that is of type com.marklogic.xcc.ContentSource
<bean id="marklogicRepository" class="org.example.repository.ingestion.MarkLogicRepositoryImpl">
<property name="contentSource" ref="contentSource" />
</bean>
The issue is that the contentSource bean is of type JndiObjectFactoryBean and not com.marklogic.xcc.ContentSource. Is there something I'm missing to get a proper ContentSource from the JndiObjectFactoryBean?
It turns out the above code actually worked, my IDE was complaining about types but Spring will automatically cast the object stored inside JndiObjectFactoryBean to the target type at runtime.
Maybe try XQJ?
https://github.com/cfoster/xqj-pool-example/blob/master/src/main/java/simple/WithJNDI.java
http://xqj.net/
The XQuery API for Java
A standard Java interface to XML DataSources which support XQuery 1.0.
The XQJ API is to XML Databases as the JDBC API is to Relational Databases.
Is a light-weight design and is very easy to pick up.

Referencing a value from a spring config

First a bit of setup info:
I have a multi-tenant spring based application. The multi-tenant enabling library is an in-house developed tool where I work that I have to use. How it works is that there is an interceptor that sets in front of the servlet for the application. Upon a request hitting the servlet it loads a tenant specific spring config for "stuff" needed for the tenant specified on the url hitting the servlet.
As stated, the above is just a bit of background. Now to the issue/question:
What I want to do is to create, in the tenant configuration that is loaded, a value that I can use to inject where I need. So, is there a way I can just define a constant in a spring config and then reference it via #Value or #Resource in java code?
There will be no bean implementation behind it, it would just be purely and only a key/value that I can reference where needed in my application by name. So, something to the effect of:
<bean name="MyIdentifier">
<property name="theId" value="1001" />
</bean>
And then can I do something like?
#Value{MyIdentifier.theId}
String theId;
And have Spring be aware of and inject the value. The problem is that doing something like above Spring complains there is no implementation for the bean. Notice, no class specified for the bean. The reason I want to do this is every tenant config file will contain this bean, but the actual value will vary per tenant.
Is there some other type to use in the config to do this? If so, what schemas have to be on the config?
I am guessing I am either trying to make Spring do something not intended, or, this is so simple I cannot see it since I have stared at it too long. Anyway, thanks for the help.
You can not create bean tag in configuration file without providing class implementation. If you want to inject the value of fields, you have to go for properties file instead.
Create property file as below:
application.properties
theId=1001
Load property file in your configuration:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
And access the property in your concrete class:
#Value("${theId}")
String theId;

Use Spring ressource bundle with Hibernate Validator

First time posting here.
I'm developing a JSON webservice API and I'm tring to use custom validation message with no success.
Here is my setup (focus on component involved in my problem. I also use MyBatis, jUnit...) :
Tomcat 8.0.14
Spring 4.1.1
Jersey 2.13
Jersey-spring3 2.13
Jersey-bean-validation
Hibernate Validator 5.0.0.Final
Bean property validation and class-level validation work fine.
Now I'm trying to setup custom error validation messages.
I don't wan't to use the JSR-303 /META-INF/ValidationMessages.properties but I wan't to use a spring managed bundle.
In my applicationContext.xml, I defined :
<bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource">
<ref bean="messageSource" />
</property>
</bean>
<bean name="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="configuration/messages/validation" />
</bean>
I also create a /WEB-INF/classes/configuration/messages/validation_fr_FR.properties with some properties :
model.error=Modèle invalide
Now when I try to validate my Bean I get this in my logs :
15:47:14,300 DEBUG http-nio-8080-exec-2 resourceloading.PlatformResourceBundleLocator:72 - ValidationMessages not found.
15:47:45,707 DEBUG http-nio-8080-exec-2 resourceloading.PlatformResourceBundleLocator:69 - org.hibernate.validator.ValidationMessages found.
No mention to my bundle here...
In my JSON response, I get :
{model.error} (path = EventServiceAPIImpl.createOrUpdateEvent.arg0, invalidValue = fr.bz.pdcv.bean.Event#d99af88)
{model.error} is not replaced with my custom message.
I think my ReloadableResourceBundleMessageSource is overridden by Hibernate Validator default configuration. But why ?
I overload google and stackoverflow to find a solution, I didn't find anythings which can help me
Does someone encounter the same issue ?
Thank you !
Though I guess i am late but it may help someone else.
Rename your validation_fr_FR.properties with ValidationMessages.properties file and put that inside the folder 'src\main\resources'.
So your final path will be as follows:
src\main\resources\ValidationMessages.properties
Restart the server and try to render the validation.
U no more need the LocalValidatorFactoryBean and ResourceBundleMessageSource
Hibernate basically looks for the same file name in the default directory and overwrites the default ValidationMessages.properties

Migration to Spring WS 2.0 failed due to lack of bean endpoint mapping?

We used the PayloadRootQNameEndpointMapping to map endpoint scripts (based on a scripting language like groovy or something else) to a given root QName. We recently tried to migrate spring ws to version 2.0. The javadoc of the PayloadRootQNameEndpointMapping shows that the class is marked as deprecated.
PayloadRootQNameEndpointMapping Deprecated as of Spring Web Services 2.0, in favor of PayloadRootAnnotationMethodEndpointMapping
Since annotations are static we can't provide a dynamic concept for scripting endpoints. Until now we could generically map the Bean which is handling a script endpoint (provided with a script file and some contexts) to the root QName.
Short: How can we achieve the good old bean endpoint to Root QName mapping without using the deprecated API? Any ideas?
Thank you in advance.
Can you use something like the SimpleMethodEndpointMapping to write your own dispatcher? Check the link for the source
You can use more general XPathPayloadEndpointMapping where xpath will point to root element.
<bean id="endpointMapping" class="org.springframework.ws.server.endpoint.mapping.XPathPayloadEndpointMapping">
<property name="expression" value="local-name(//*[1])" />
<property name="endpointMap">
<map>
<entry key="rootElement" value="endpointRef" />
</map>
</property>
</bean>

Categories