Mule RegistrationException - jaxb

So this one makes me wonder. I have a Mule integration with a couple of flows in it and they all work nice. Except for the last one.
If I end that one in a file endpoint, it works as expected. But if I end it in my WS POST service.. I get an error complaining about multiple JAXB contexts.
I have multiple JAXB contexts but as said they work fine if I'm not trying to post my JSON to that REST service.
And somehow, I can't see that my HTTP endpoint has anything to do with JAXB either so I guess it's a misguiding error?
But then, what is wrong with my HTTP endpoint, I use it as inbound in the other flows and also tried to create an entirely new one for this particular flow, but still this nagging about JAXB.
<http:request-config name="WS" host="127.0.0.1" port="81" doc:name="HTTP Request Configuration" basePath="WSService"/>
<http:request-config name="MQService" host="127.0.0.1" port="82" doc:name="HTTP Request Configuration" />
<mulexml:jaxb-context name="JAXB_A" packageNames="se.razorlib.SystemAProduct" doc:name="JAXB Context"/>
<mulexml:jaxb-context name="JAXB_B" packageNames="se.razorlib.SystemAPurchase" doc:name="JAXB Context"/>
<mulexml:jaxb-context name="JAXB_C" packageNames="se.razorlib.SystemAOrder" doc:name="JAXB Context"/>
<context:property-placeholder location="razorlib.properties"/>
<flow name="ProductToSystemA">
....
<http:request config-ref="WS" path="Product/REST/GetProduct/{id}/{index}" method="GET" doc:name="WS">
<http:request-builder>
<http:uri-param paramName="id" value="${WS.id}"/>
<http:uri-param paramName="index" value="1"/>
</http:request-builder>
</http:request>
.....
</flow>
<flow name="PurchaseToSystemA">
.....
</flow>
.....
and this particular flow
<flow name="PurchaseDeliver">
<file:inbound-endpoint path="C:\temp\fileIn" responseTimeout="10000" doc:name="FileIn"/>
<mulexml:jaxb-xml-to-object-transformer returnClass="se.razorlib.SystemAPurchase.Header" encoding="UTF-16" jaxbContext-ref="JAXB_B" doc:name="XML to JAXB Object"/>
<custom-transformer returnClass="java.util.List" encoding="utf-16" class="se.razorlib.Transformer.Map2ZZPurchase" doc:name="Map2ZZ"/>
<json:object-to-json-transformer encoding="UTF-16" doc:name="Object to JSON"/>
<logger message="'Payload ' #[payload]" level="INFO" doc:name="Logger"/>
<http:request config-ref="WS" path="PurchaseSvc/REST/Deliver/{id}" method="POST" doc:name="WSDeliver">
<http:request-builder>
<http:uri-param paramName="id" value="${WS.id}"/>
</http:request-builder>
</http:request>
<!-- <file:outbound-endpoint path="C:\temp\fileOut" responseTimeout="10000" doc:name="File" outputPattern="inkop2ZZ-#[function:dateStamp].json" mimeType="text/json" encoding="UTF-8"/> -->
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="Oh no!!" level="INFO" doc:name="Logger"/>
<file:outbound-endpoint path="C:\temp\fileError" responseTimeout="10000" doc:name="File" outputPattern="error-inkop2ZZ-#[function:dateStamp].xml" mimeType="text/xml" encoding="UTF-8"/>
</catch-exception-strategy>
</flow>
The error I get is this one:
Root Exception stack trace:
org.mule.api.registry.RegistrationException: More than one object of type class javax.xml.bind.JAXBContext registered but only one expected.
Regards

I have seen a similar scenario's, this might be because of Multiple jaxb-context. Resolved by placing all the packages in one Context
<mulexml:jaxb-context name="JaxbContext" packageNames="se.razorlib.SystemAProduct:se.razorlib.SystemAPurchase:se.razorlib.SystemAOrder"/>
In flow
<mulexml:jaxb-xml-to-object-transformer returnClass="se.razorlib.SystemAPurchase.Header" encoding="UTF-16" jaxbContext-ref="JaxbContext" doc:name="XML to JAXB Object"/>
Hope this helps.

First I would not be surprised that the file endpoint gave no error. The file doesn't care what it gets. It just wants ones and zeros. I somewhat agree with the answer above but I think you only need to reference the package for the three Java bindings.
<mulexml:jaxb-context name="myJaxb" packageNames="se.razorlib"/>
You are defining the context for JAXB transformations. The package says it all.

Related

${aspnet-request-posted-body} not returning data

hi I am trying to use Http target to send the log to an API.
nlog.config:
<targets>
<target name='HTTP'
type='HTTP'
URL='https://localhost:44331/api/logs'
Method='POST'
BatchSize='1'
MaxQueueSize='2147483647'
IgnoreSslErrors='true'
FlushBeforeShutdown='true'
ContentType='application/json'
Accept='application/json'
DefaultConnectionLimit='2'
Expect100Continue='false'
UseNagleAlgorithm='true'
ConnectTimeout='30000'
InMemoryCompression='true'>
<layout type='JsonLayout'>
<attribute name='sourcetype' layout='_json' />
<attribute name='host' layout='${machinename}' />
<attribute name='RequestBody' layout='${aspnet-request-posted-body}' />
<attribute name='event' encode='false'>
<layout type='JsonLayout'>
<attribute name='level' layout='${level:upperCase=true}' />
<attribute name='source' layout='${logger}' />
<attribute name='thread' layout='${threadid}' />
<attribute name='message' layout='${message}' />
<attribute name='utc' layout='${date:universalTime=true:format=yyyy-MM-dd HH\:mm\:ss.fff}' />
</layout>
</attribute>
</layout>
</target>
I got every attribute I added except for RequestBody.
Also logging to file and database is working fine as well as
http it is being called but without the request body data.
Any thing I am missing?
Probably you're missing the proper setup.
I will list the options:
ASP.NET (non-core)
You need to have the package NLog.Web installed
Then it should work out of the box, but I you have still issues, then force to include NLog.Web like this:
<nlog>
<extensions>
<add assembly="NLog.Web"/>
</extensions>
...
See docs
ASP.NET Core
For ASP.NET Core it depends on the version.
First of all you need the package NLog.Web.AspNetCore installed.
Also add to your config:
<extensions>
<!--enable NLog.Web for ASP.NET Core-->
<add assembly="NLog.Web.AspNetCore"/>
</extensions>
And the Setup need to call NLog.Web.AspNetCore. I would recommend to check: Use NLog in ASP.NET Core application
Make sure you have called .AddNLogWeb(); / .UseNLog() (dependent on the ASP.NET Core version)
Still issues?
Still issues? There could be various other reasons and for now that's guessing. The target you used could choke on the length of the value etc.
I would recommend: Test it with a FileTarget or ConsoleTarget
and as check the internal log! - that will show a good error message if there is something wrong.
I faced the same and solution is in few github issues and thanks to Julian.
1.https://github.com/NLog/NLog.Web/issues/548
FilePath=C:\Users\user\myapp\bin\Debug\netcoreapp3.1\nlog.development.config
2020-07-21 11:05:29.1792 Warn Exception in layout renderer. Exception: System.InvalidOperationException: Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead.
at Microsoft.AspNetCore.Server.IIS.Core.HttpRequestStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at Microsoft.AspNetCore.Server.IIS.Core.WrappingStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.ReadToEnd()
at NLog.Web.LayoutRenderers.AspNetRequestPostedBody.BodyToString(Stream body)
at NLog.Web.LayoutRenderers.AspNetRequestPostedBody.DoAppend(StringBuilder builder, LogEventInfo logEvent)
at NLog.LayoutRenderers.LayoutRenderer.RenderAppendBuilder(LogEventInfo logEvent, StringBuilder builder)
https://github.com/NLog/NLog.Web/pull/549
https://github.com/NLog/NLog.Web/issues/556
Adding below finally fixed the issue.
app.Use(async (context, next) => {
context.Request.EnableBuffering();
await next();
});
to here and Must be before app.UseEndpoints
public virtual void Configure(IApplicationBuilder app, IWebHostEnvironment env)
NLog.Web.AspNetCore v5.1 changes ${aspnet-request-posted-body} so it requires middleware to work:
app.UseMiddleware<NLog.Web.NLogRequestPostedBodyMiddleware>();
The middleware will ensure context.Request.EnableBuffering(); is called when necesary, so one doesn't have to call it explictly.
See also: https://github.com/NLog/NLog.Web/wiki/HTTP-Request-Logging

Spring Integration - Flow process with erro handling

I'm continuing to study SI and in the same time i'm trying to build an application.
My application flow is this:
Read XML file and split each tag
Each tag have define an attribute called "interval", and i need to create a job that will be repeated, according to this value.
When the job execution is terminated, need to invoke a Web Service to store information
If WBS invokation fails, try to send info by email
Right now i'm arrived on point one ( :D ) of this flow, now i'm trying to move forward and first check the error handling (point 4 of the flow).
This is the actual configuration that i have and this works fine splitting the tag and then invoking the right service-activator:
<context:component-scan base-package="it.mypkg" />
<si:poller id="poller" default="true" fixed-delay="1000"/>
<si:channel id="rootChannel" />
<si-xml:xpath-splitter id="mySplitter" input-channel="rootChannel" output-channel="routerChannel" create-documents="true">
<si-xml:xpath-expression expression="//service" />
</si-xml:xpath-splitter>
<si-xml:xpath-router id="router" input-channel="routerChannel" evaluate-as-string="true">
<si-xml:xpath-expression expression="concat(name(./node()), 'Channel')" />
</si-xml:xpath-router>
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
The endChannel will need to receive all messages from the several channel (sent by the router) and then invoke the WBS. Right now i'm jkust creating classes to check if the flow will works or not.
The remaining part of my applicationContext.xml is this:
<!-- Create a poller that will be used by endChannel -->
<si:poller id="poller" default="true" fixed-delay="1000" error-channel="failedInvocationChannel" />
<!--- take messages from serviceChannel and redirect to endChannel, that is responsable to receive messages from all channels created by the router -->
<si:service-activator input-channel="serviceChannel" output-channel="endChannel">
<bean class="it.mypkg.Service" />
</si:service-activator>
<!-- end channel is a queue -->
<si:channel id="endChannel">
<si:queue capacity="10"/>
</si:channel>
<!-- Messages are taken from the queue.. -->
<si:service-activator input-channel="endChannel">
<bean class="it.mypkg.Invokator" />
</si:service-activator>
<!-- Service activator that handle the errors on the queue -->
<si:channel id="failedInvocationChannel" />
<si:service-activator input-channel="failedInvocationChannel">
<bean class="it.mypkg.Resubmitter" />
</si:service-activator>
but when i run my application i got this error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#0': Cannot create inner bean 'org.springframework.integration.handler.MessageHandlerChain#0$child#1.handler' of type [org.springframework.integration.config.ServiceActivatorFactoryBean] while setting bean property 'handlers' with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#0$child#1.handler': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.integration.channel.QueueChannel] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveInnerBean(BeanDefinitionValueResolver.java:313)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:122)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:197)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:172)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:158)
I've read a lot and i'm a little bit confused about all the components that can be used... maybe my error is because i'm trying to use components in the wrong way...
EDIT: Configuration updated with error-channel on poller and removed chain to handle the error
<si:service-activator ref="endChannel" method="dispatch" />
You can't use a ref to a channel in a service activator.
Also, it's better to give elements like chains an id so exceptions are easier to debug.
Also, you generally shouldn't be manipulating the errorChannel header; it's better to add an error-channel to the poller and route the error flow that way.

Is there a way to exclude a project from being logged?

I have an app where sometimes I'd like to log in Debug mode. Unfortunately i link with a third party lib that I can't rebuild. It was built to use log4net and on the Debug mode it is very verbose.
I don't want to get any notifications from that library. I do however want to get log notifications from all other code that wants to write.
Is there a way to exclude a namespace or library from logging when using either the SMTPAppender or RollingFile Appender writers?
You could use a filter, e.g.
<filter type="log4net.Filter.LoggerMatchFilter">
<!-- allows this sub-namespace to be logged... -->
<loggerToMatch value="Noisy.Namespace.But.Important" />
</filter>
<filter type="log4net.Filter.LoggerMatchFilter">
<!-- ...but not the rest of it -->
<loggerToMatch value="Noisy.Namespace" />
<acceptOnMatch value="false" />
</filter>
More details from this article.
Im imagine that you are using a configuration where you set only the root level of your logging infrastructure:
<root>
<level value="DEBUG" />
<appender-ref ref="A1" />
</root>
However it is possible to define other levels of logging using the logger names. If you or the third party app followed standard practices, your loggers are named after the class they live with its namespace, so you will have loggers called
MyApp.Main
MyApp.Business
MyApp.Business.Messages
ThirdParty.API
etc...
What you can do in this case is declare the logging at the namespace level you're interested in. For example to log only what lives under MyApp.Main add the following
<logger name="MyApp.Main">
<level value="DEBUG" />
<appender-ref ref="A1" />
</logger>
and remove any appender from the root level. Then you only log the loggers that live under the MyApp name. See the documentation for more info.
If you are unlucky and the loggers don't conform to this hierarchy, you can still filter them out by using a LoggerMatchFilter in your appender; this lets you either define what logger can pass, or what loggers cannot. There are lots of filters, feel free to explore them

Mule ESB JAXB XML To Object Transformer Better Way?

Mule 3.3 can automatically unmarshall an XML string to an object using JAXB given that:
1. you first register your jaxb annotated classes with spring.
2. there is a component that requires such type as input
So I have managed to do the transformation, but I had to create a "DumbTransformer" that does nothing. It has a method that returns the same object it receives. I need it in order to trigger the XML to Object conversion so that I can further process the message.
Flow Example:
<spring:beans>
<spring:bean id="dumbTransformer" class="foo.bar.DumbTransformer"/>
</spring:beans>
<flow name="main" doc:name="main">
<vm:inbound-endpoint path="in" doc:name="VM" />
<component doc:name="Java">
<spring-object bean="dumbTransformer"/>
</component>
<splitter expression="#[payload.items]" doc:name="Split Items"/>
<logger message="#[payload]" level="INFO" doc:name="Log Item"/>
<vm:outbound-endpoint path="out" doc:name="VM" />
</flow>
DumbTransformer.java
package foo.bar;
#ContainsTransformerMethods
public class InvoiceUnmarshaller extends AbstractTransformer {
#Transformer
public MyJaxbAnnotatedClass foo(#Payload MyJaxbAnnotatedClass i) {
return i;
}
}
Is there a way to acomplish this without having to create such DumbTransformers?
Thanks.
As you guessed it, the JAXB deserialization doesn't occur because there is no component to satisfy:
there is a component that requires such type as input
So what if you had an auto-transformer to do just that:
<auto-transformer returnClass="foo.bar.MyJaxbAnnotatedClass" />
The Mule XML Module provides OOTB a JAXB Transformer. I would rather leverage mule capabilities whenever possible rather than writing custom code

Generalize http:outbound-gateway reply-channel

Given a gateway that handles service calls to a ws. My goal is to supply the http:outbound-gateway's reply-channel using header-enricher since I'll be adding multiple methods to gateway and I would like to make use of only 1 http:outbound-gateway
I can currently receive the response up to groovy script (2) BUT it doesn't seem to want to return the results to the actual method that calls the service
Any help would be appreciated. Thanks!
<gateway id="registryService" service-interface="RegistryService">
<method name="create" request-channel="create-request-channel"
reply-channel="create-reply-channel" />
</gateway>
<chain input-channel="create-request-channel" output-channel="create-request-fulfillment-channel">
<transformer>
// groovy script that contains the method to be called in the ws (1)
</transformer>
<object-to-json-transformer/>
<header-enricher>
<reply-channel overwrite="true" ref="create-reply-fulfillment-channel" />
</header-enricher>
</chain>
<http:outbound-gateway request-channel="create-request-fulfillment-channel"
extract-request-payload="true"
expected-response-type="java.lang.String"
url="http://localhost:4567" http-method="POST" />
<chain input-channel="create-reply-fulfillment-channel"
output-channel="create-reply-channel">
<json-to-object-transformer type="JsonRpcResponse"/>
<transformer>
//groovy script to manipulate response (2)
</transformer>
</chain>
Do the following:
Each method of your gateway should enrich message with some unique 'routing' header value:
<gateway id="registryService" service-interface="RegistryService">
<method name="create" request-channel="http-request-channel"
reply-channel="registryService-create-responseChannel">
<header name="routingHeader" value="registryService-create" />
</method>
</gateway>
And then send message straight forward to outbound gateway:
<http:outbound-gateway request-channel="http-request-channel"
response-channel="http-response-channel"
extract-request-payload="true"
expected-response-type="java.lang.String"
url="http://localhost:4567" http-method="POST" />
Http outbound gateway sends request to the remote server and then forward response to http-response-channel. To this channel is attached header value router, which basis on the value of routing header, sends (routes) message to the appropriate channel:
<header-value-router input-channel="http-response-channel" header-name="routingHeader">
<mapping value="registryService-create" channel="registryService-create-responseChannel" />
<mapping value="someOtherService-otherMethod" channel="someOtherService-otherMethod-responseChannel" />
</header-value-router>
Of course you don't need to send it back directly to the gateway - you can add some additional processing between those components, and all the time you can route message basis on the header value.
It's simpler than hacks with groovy and I use it myself - proven that works ;)

Resources