Mule - Object To XML with JAXB - jaxb

I'm using Mule 3.8 to get some JSON data which I turn to Java and then to XML files. Everything works until my File endpoint where it all ends in disaster:
Message : Could not find a transformer to transform
"SimpleDataType{type=java.io.ByteArrayOutputStream, mimeType='text/xml',
encoding='null'}" to "SimpleDataType{type=java.io.InputStream,
mimeType='*/*', encoding='null'}".
Payload : <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Header ....></Header>
Payload Type : java.io.ByteArrayOutputStream
..and all i get is dozens of empty .xml files..
I guess somehow I have to tranform my payload to something the file component could actually take and turn into a file, or is this something I have to do manually in a Java component?
Regards
EDIT - forgot the config
<flow name="Product">
<file:inbound-endpoint path="C:\temp\fileIn" responseTimeout="10000" doc:name="File"/>
<logger message="#[payload != null]" level="INFO" doc:name="Logger"/>
<json:json-to-object-transformer returnClass="java.util.List" encoding="UTF-8" doc:name="JSON to ObjectList"/>
<collection-splitter doc:name="Collection Splitter"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<custom-transformer returnClass="se.131.Product.Header" encoding="UTF-8" class="se.131.Tranformer.Map2Product" doc:name="MapToProduct" mimeType="application/xml"/>
<mulexml:jaxb-object-to-xml-transformer name="myMarshaller" jaxbContext-ref="JAXB_Context" doc:name="JAXB Object to XML" encoding="UTF-8" mimeType="application/xml"/>
<logger message="#[payload]" level="INFO" doc:name="Logger"/>
<file:outbound-endpoint path="C:\temp\fileOut" responseTimeout="10000" doc:name="File" outputPattern="Product-#[function:dateStamp].xml" mimeType="text/xml"/>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<logger message="Oh no!!" level="INFO" doc:name="Logger"/>
</catch-exception-strategy>
</flow>

Try with placing <object-to-string-transformer> just before File outbound endpoint and check ...
The File endpoint expect String format of the payload to create the file

Related

Azure API Management WSDL Import Failing on SOAP Encoding's Array Type

I'm trying to create an API from a WSDL and currently getting this error back from Azure APIM during the import step:
Error: Parsing error : Line 17, position 22: Unable to import API from WSDL: Undefined
complexType 'http://schemas.xmlsoap.org/soap/encoding/:Array' is used as a base for
complex type restriction.
I'm gathering that the Array type is not WSI-compliant, but would love insight as to how I can tinker with the WSDL to make it work? I don't own the service which generated the WSDL, but the WSDL hasn't changed since it was incepted and the provider has said it's okay for us to mess with it to get the Azure APIM import step to work. Just meaning, since Azure APIM's a passthrough what can I slice out of the WSDL which would still (a) let Azure APIM import it, and (b) allow the calls to successfully flow through Azure APIM at runtime?
I slimmed down the WSDL to this, but let me know if anything looks off as the original WSDL is ~5,500 lines:
<?xml version="1.0"?>
<definitions
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="urn:ChestersCopperpotsServiceSoap"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:atls="http://tempuri.org/vc/atl/server/"
targetNamespace="urn:ChestersCopperpotsServiceSoap"
xmlns="http://schemas.xmlsoap.org/wsdl/"
>
<types>
<s:schema targetNamespace="urn:ChestersCopperpotsServiceSoap" attributeFormDefault="qualified" elementFormDefault="qualified">
<s:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
<s:complexType name="CMessage">
<s:sequence>
<s:element name="Code" type="s:int"/>
<s:element name="Text" type="s:string"/>
</s:sequence>
</s:complexType>
<s:complexType name="GetMessages_return_Array">
<s:complexContent>
<s:restriction base="soapenc:Array">
<s:attribute ref="soapenc:arrayType" wsdl:arrayType="s0:CMessage[]"/>
</s:restriction>
</s:complexContent>
</s:complexType>
<s:complexType name="MyHeader">
<s:sequence>
<s:element name="m_SessionID" type="s:string"/>
</s:sequence>
</s:complexType>
</s:schema>
</types>
<message name="GetMessagesIn">
</message>
<message name="GetMessagesOut">
<part name="return" type="s0:GetMessages_return_Array"/>
</message>
<message name="m_Header">
<part name="m_Header" type="s0:MyHeader"/>
</message>
<portType name="ChestersCopperpotsServiceSoap">
<operation name="GetMessages">
<input message="s0:GetMessagesIn"/>
<output message="s0:GetMessagesOut"/>
</operation>
</portType>
<binding name="ChestersCopperpotsServiceSoap" type="s0:ChestersCopperpotsServiceSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc"/>
<operation name="GetMessages">
<soap:operation soapAction="#GetMessages" style="rpc"/>
<input>
<soap:body use="encoded" namespace="urn:ChestersCopperpotsService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<soap:header message="s0:m_Header" part="m_Header" use="encoded" namespace="urn:ChestersCopperpotsService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</input>
<output>
<soap:body use="encoded" namespace="urn:ChestersCopperpotsService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
<soap:header message="s0:m_Header" part="m_Header" use="encoded" namespace="urn:ChestersCopperpotsService" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
</output>
</operation>
</binding>
<service name="ChestersCopperpotsService">
<port name="ChestersCopperpotsServiceSoap" binding="s0:ChestersCopperpotsServiceSoap">
<soap:address location="http://localhost:80/ChestersCopperpots/ccSOAP.dll?Handler=Default"/>
</port>
</service>
</definitions>
Full message stack from Azure APIM is:
Informational: ParsingXMLStarted : Started parsing XML
Informational: ParsingXMLComplete : Completed parsing XML
Verbose: WsdlImportRuleVerifyWadl11Schema : WSDL validated against XML Schema
Informational: WsdlPrecheckComplete : Completed WSDL verification. WSDL is considered valid.
Informational: WsdlParsingStarted : Service : Endpoint :
Informational: WsdlIdentification : WsdlVersion: 'Wsdl11' TargetNamespace: 'urn:ChestersCopperpotsServiceSoap'.
Informational: LoadedSchema : Target Namespace: 'urn:ChestersCopperpotsServiceSoap'.
Informational: LoadedSchemas : Loaded '1' schemas.
Informational: LoadedTypes : Loaded '0' types.
Informational: LoadedMessages : Loaded '3' messages.
Informational: LoadedInterfaces : Loaded '1' interfaces.
Informational: LoadedBindings : Loaded '1' bindings.
Informational: LoadedServices : Loaded '1' services.
Informational: WsdlParsingComplete : Parsed 1 operations and 3 messages
Informational: ApiType : Creating SOAP Passthrough API
Informational: APICreated : Name : chesterscopperpotsservice Service Url: http://localhost:80/ChestersCopperpots/ccSOAP.dll?Handler=Default
Informational: XsdParsing : Starting to parse urn:ChestersCopperpotsServiceSoap
Error: Parsing error : Line 17, position 22: Unable to import API from WSDL: Undefined complexType 'http://schemas.xmlsoap.org/soap/encoding/:Array' is used as a base for complex type restriction.
my money is on this part (which in lack of row #, I suspect this is where the error get's triggered). The SOAP-to-REST transformation in APIM only supports "embedded" arrays, whereas yours is referring to another definition ("s0.CMessage" above). Try replacing that bit with
<s:complexType name="GetMessages_return_Array">
<sequence>
<element name="ArrayOfCMessages" type="CMessage" minOccurs="1" maxOccurs="1"/>
</sequence>
</s:complexType>

Log4j2 - LogManager.getLogger("name") not finding custom loggers

Log4j2 - LogManager.getLogger("name") not finding custom loggers.
All of the following return the same logger - that being the Root logger for the class that this code is in. I would like to think these would all be different and I would get my 3 custom ones back for the first 3 calls.
Note the files specified by the appenders are created, but no logs are sent to them.
Logger _l = (Logger) LogManager.getLogger("Global");
_l = (Logger) LogManager.getLogger("fakeswitch");
_l = (Logger) LogManager.getLogger("fakeswitch_two");
_l = (Logger) LogManager.getLogger();
I create custom loggers using the following:
ComponentBuilder triggeringPolicy = configurationBuilder.newComponent("Policies")
.addComponent(configurationBuilder.newComponent("TimeBasedTriggeringPolicy").
addAttribute("interval", "1"));
AppenderComponentBuilder log4jFileAppenderBuilder = configurationBuilder.
newAppender(pName + "_SmdrDailyRollingFileAppender", "RollingFile");
log4jFileAppenderBuilder.addAttribute("filename", pLogFilename);
log4jFileAppenderBuilder.addAttribute("filePattern", pLogFilenamePattern);
log4jFileAppenderBuilder.addComponent(triggeringPolicy);
// Configure the PatternLayout
LayoutComponentBuilder layoutComponentBuilder = configurationBuilder.newLayout("PatternLayout").
addAttribute("pattern", DEBUG_PATTERN_LAYOUT_STRING);
log4jFileAppenderBuilder.add(layoutComponentBuilder);
// Add it back into configuration
configurationBuilder.add(log4jFileAppenderBuilder);
// https://logging.apache.org/log4j/2.x/manual/customconfig.html
LoggerComponentBuilder logger = configurationBuilder.newLogger(pName, Level.DEBUG);
logger.add(configurationBuilder.newAppenderRef(pName + "_SmdrDailyRollingFileAppender"));
logger.addAttribute("additivity", false);
configurationBuilder.add(logger);
// Actually use it
LoggerContext _loggerContext = Configurator.initialize(configurationBuilder.build());
The equiv XML from writeXmlConfiguration is:
<?xml version="1.0" ?>
<Configuration>
<Appenders>
<RollingFile name="Global_SmdrDailyRollingFileAppender" filename="ps/debug/SMDR_DEBUG.txt"
filePattern="ps/debug/SMDR_DEBUG_%d{yyyyMMdd}.txt.gz">
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<PatternLayout pattern="%d{MM.DD.yy-HH:mm:ss} %m%n"/>
</RollingFile>
<RollingFile name="fakeswitch_SmdrDailyRollingFileAppender" filename="ps/debug/SMDR_DEBUG_fakeswitch.txt"
filePattern="ps/debug/SMDR_DEBUG_fakeswitch_%d{yyyyMMdd}.txt.gz">
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<PatternLayout pattern="%d{MM.DD.yy-HH:mm:ss} %m%n"/>
</RollingFile>
<RollingFile name="fakeswitch_two_SmdrDailyRollingFileAppender"
filename="ps/debug/SMDR_DEBUG_fakeswitch_two.txt"
filePattern="ps/debug/SMDR_DEBUG_fakeswitch_two_%d{yyyyMMdd}.txt.gz">
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<PatternLayout pattern="%d{MM.DD.yy-HH:mm:ss} %m%n"/>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="Global" level="DEBUG" additivity="false">
<AppenderRef ref="Global_SmdrDailyRollingFileAppender"/>
</Logger>
<Logger name="fakeswitch" level="DEBUG" additivity="false">
<AppenderRef ref="fakeswitch_SmdrDailyRollingFileAppender"/>
</Logger>
<Logger name="fakeswitch_two" level="DEBUG" additivity="false">
<AppenderRef ref="fakeswitch_two_SmdrDailyRollingFileAppender"/>
</Logger>
</Loggers>
</Configuration>
This was answered for me by Piotr P Karwasz.
This only works if the LoggerContext has not been initialized yet. Since
every call to a LogManager method initializes a LoggerContext, it is
almost certainly too late to use Configurator.initialize.
Use Configuration.reconfigure instead, which works in all cases.
Piotr
--- my code change was
LoggerContext _loggerContext = Configurator.initialize(configurationBuilder.build());
to
Configurator.reconfigure(configurationBuilder.build());

log4j2 RollingFileAppender old file gets removed after 7 rollovers

I use following log4j RollingFile appender in my webapp.
<Appenders>
<RollingFile name="logFile"
fileName="${env:SYSTEM_LOGS}/${env:LOG_FILE_NAME}.log" immediateFlush="true"
filePattern="${env:SYSTEM_LOGS}/${env:LOG_FILE_NAME}.log.%d{yyyy_MM_dd.HH_mm_ss}.%i">
<PatternLayout pattern="%d{yyyyMMdd-HHmmss.SSS}|%X{username}|%-5p|%t| %-100m (%c{1})%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
With filePattern="${env:SYSTEM_LOGS}/${env:LOG_FILE_NAME}.log.%d{yyyy_MM_dd.HH_mm_ss}.%i", when log is rolled over, old file gets renamed to a filename with an index number (specified with %i), so all old files should get renamed and should be preserved.
I rollover the log programmatically with following code.
org.apache.logging.log4j.Logger logManagerLogger = LogManager.getLogger();
Map<String, org.apache.logging.log4j.core.Appender> appenders = ((org.apache.logging.log4j.core.Logger) logManagerLogger).getAppenders();
appenders.forEach((appenderName, appender) -> {
if (appender instanceof RollingFileAppender) {
LOGGER.info("Switching log for appender " + appenderName);
((RollingFileAppender) appender).getManager().rollover();
}
});
But, after 7 rollovers, the existing file gets removed (not renamed according to the specified filePattern) and log is continued in a new file.
What could be the issue here?
set DefaultRolloverStrategy(default is 7), In your config will be:
<Appenders>
<RollingFile name="logFile"
fileName="${env:SYSTEM_LOGS}/${env:LOG_FILE_NAME}.log" immediateFlush="true"
filePattern="${env:SYSTEM_LOGS}/${env:LOG_FILE_NAME}.log.%d{yyyy_MM_dd.HH_mm_ss}.%i">
<PatternLayout pattern="%d{yyyyMMdd-HHmmss.SSS}|%X{username}|%-5p|%t| %-100m (%c{1})%n"/>
<Policies>
<OnStartupTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="100"/>
</RollingFile>
</Appenders>
now, it will have 100 log file to rollover.
If you want unlimited rollingfile,
According to Log4j2 documentation, from release 2.8, it can be done by setting fileIndex attribute to nomax. For example:
<DefaultRolloverStrategy fileIndex="nomax" />

Mule - JMS (ActiveMQ) Reconnection

This is my mule flow 1:
HTTP > Payload String > Logger > JMS /normalqueue
The first flow has an error handling:
File (Write a file per message handled)
Flow 2:
JMS /normalqueue > Logger
Recovery flow (Invoked with a groovy script):
File (Read file) > File to String > Flow reference (To First Flow again)
This is the XML from Mule:
<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
<jms:activemq-connector name="Active_MQ" username="admin" password="admin" brokerURL="tcp://192.168.198.131:61616" validateConnections="true" doc:name="Active MQ" persistentDelivery="true">
<reconnect blocking="false" frequency="6000"/>
</jms:activemq-connector>
<file:connector name="File" writeToDirectory="C:\errors" autoDelete="true" streaming="true" validateConnections="true" doc:name="File"/>
<flow name="lab-file-catchFlow">
<http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
<set-payload value="#[message.payloadAs(java.lang.String)]" doc:name="Set Payload"/>
<logger message="Started message: #[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
<jms:outbound-endpoint queue="activemq" connector-ref="Active_MQ" doc:name="JMS">
<jms:transaction action="ALWAYS_BEGIN"/>
</jms:outbound-endpoint>
<catch-exception-strategy doc:name="Catch Exception Strategy">
<file:outbound-endpoint path="C:\errors" connector-ref="File" responseTimeout="10000" doc:name="File"/>
</catch-exception-strategy>
</flow>
<flow name="flow-recovery" initialState="stopped" processingStrategy="synchronous">
<file:inbound-endpoint path="C:\errors" connector-ref="File" responseTimeout="10000" doc:name="File"/>
<file:file-to-string-transformer doc:name="File to String"/>
<logger message=" Recovery message: #[message.payloadAs(java.lang.String)]" level="ERROR" doc:name="Logger"/>
<flow-ref name="lab-file-catchFlow" doc:name="Flow Reference"/>
</flow>
<flow name="lab-file-catchFlow2" processingStrategy="synchronous">
<jms:inbound-endpoint queue="activemq" connector-ref="Active_MQ" doc:name="JMS"/>
<logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
</flow>
<flow name="lab-file-catchFlow1" >
<http:listener config-ref="HTTP_Listener_Configuration" path="/modify" doc:name="HTTP"/>
<scripting:component doc:name="Groovy">
<scripting:script engine="Groovy"><![CDATA[ if(muleContext.registry.lookupFlowConstruct('flow-recovery').isStopped())
{
muleContext.registry.lookupFlowConstruct('flow-recovery').start();
return 'Started';
} else
{
muleContext.registry.lookupFlowConstruct('flow-recovery').stop();
return 'Stopped';
}]]></scripting:script>
</scripting:component>
<set-payload value="#[message.payloadAs(java.lang.String)]" doc:name="Set Payload"/>
<logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
</flow>
I stop service from ActiveMQ, it store a file with the messages from the error handling and I receive the typical error:
Cannot process event as "Active_MQ" is stopped
Then, I run the ActiveMQ service again and start the recovery flow with a groovy script. That flow recover all messages, converts to string and return to the first flow to requeue.
The problem is that mule doesn't detect when service is running again, I need to restart the mule project to detect it.
Is there any way auto detect when the activeMQ is running again with Mule?
By <reconnect-forever/>, Mule will keep re-trying to connect to ActiveMQ
<jms:activemq-connector name="Active_MQ" username="admin" password="admin" brokerURL="tcp://192.168.198.131:61616" validateConnections="true" doc:name="Active MQ" persistentDelivery="true">
<reconnect-forever/>
</jms:activemq-connector>

Active Sync Client Sync Message, status code 4 - ParseSyncKey - AirSyncPermanentException

I'm currently writing an active sync client and I've successfully managed to do a folder sync. I'm now attempting to sync the "Notes" folder (using the sync command) and it's giving me an error code 4, which Microsoft describes as "Protocol Error" -- I don't see anything wrong in the protocol that I'm sending, here is the sections from my log:
Folder sync RequestBody :
<?xml version="1.0" encoding="utf-8" ?>
<FolderSync xmlns="FolderHierarchy:">
<SyncKey>0</SyncKey>
</FolderSync>
FolderSync ResponseBody:
<?xml version="1.0" encoding="utf-8" ?>
<FolderSync xmlns="FolderHierarchy:">
<Status>1</Status>
<SyncKey>1</SyncKey>
<Changes>
<Count>12</Count>
<Add>
<ServerId>1</ServerId>
<ParentId>0</ParentId>
<DisplayName>Calendar</DisplayName>
<Type>8</Type>
</Add>
<Add>
<ServerId>2</ServerId>
<ParentId>0</ParentId>
<DisplayName>Contacts</DisplayName>
<Type>9</Type>
</Add>
<Add>
<ServerId>3</ServerId>
<ParentId>0</ParentId>
<DisplayName>Deleted Items</DisplayName>
<Type>4</Type>
</Add>
<Add>
<ServerId>4</ServerId>
<ParentId>0</ParentId>
<DisplayName>Drafts</DisplayName>
<Type>3</Type>
</Add>
<Add>
<ServerId>5</ServerId>
<ParentId>0</ParentId>
<DisplayName>Inbox</DisplayName>
<Type>2</Type>
</Add>
<Add>
<ServerId>6</ServerId>
<ParentId>0</ParentId>
<DisplayName>Journal</DisplayName>
<Type>11</Type>
</Add>
<Add>
<ServerId>7</ServerId>
<ParentId>0</ParentId>
<DisplayName>Junk E-Mail</DisplayName>
<Type>12</Type>
</Add>
<Add>
<ServerId>8</ServerId>
<ParentId>0</ParentId>
<DisplayName>Notes</DisplayName>
<Type>10</Type>
</Add>
<Add>
<ServerId>9</ServerId>
<ParentId>0</ParentId>
<DisplayName>Outbox</DisplayName>
<Type>6</Type>
</Add>
<Add>
<ServerId>10</ServerId>
<ParentId>0</ParentId>
<DisplayName>Sent Items</DisplayName>
<Type>5</Type>
</Add>
<Add>
<ServerId>11</ServerId>
<ParentId>0</ParentId>
<DisplayName>Tasks</DisplayName>
<Type>7</Type>
</Add>
<Add>
<ServerId>RI</ServerId>
<ParentId>0</ParentId>
<DisplayName>RecipientInfo</DisplayName>
<Type>19</Type>
</Add>
</Changes>
</FolderSync>
My Sync RequestBody :
<?xml version="1.0" encoding="utf-8" ?>
<Sync xmlns="AirSync:">
<Collections>
<Collection>
<SyncKey>0</SyncKey>
<CollectionId>8</CollectionId>
<DeletesAsMoves>1</DeletesAsMoves>
<GetChanges/>
</Collection>
</Collections>
</Sync>
Lists this exception:
SyncCommand_OnExecute_Exception :
Microsoft.Exchange.AirSync.AirSyncPermanentException
at Microsoft.Exchange.AirSync.SyncCommand.ParseSyncKey(SyncCollection collection)
at Microsoft.Exchange.AirSync.SyncCommand.SyncTheCollection(SyncCollection collection, Boolean createSubscription, Boolean tryNullSync)
at Microsoft.Exchange.AirSync.SyncCommand.OnExecute()
And provides the following ResponseBody :
<?xml version="1.0" encoding="utf-8" ?>
<Sync xmlns="AirSync:">
<Status>4</Status>
</Sync>
Any ideas why it is failing there? This is the first sync of the folder, so the SyncKey SHOULD be 0...
From http://msdn.microsoft.com/en-us/library/gg675447(v=exchg.80).aspx :
A Status element (section 2.2.3.162.16) value of 4 is returned if the GetChanges element is present and empty or set to 1 (TRUE) when the SyncKey element value is 0 (zero). No error is returned if the GetChanges element is absent or set to 0 (FALSE) when the SyncKey value is 0 (zero).
You have present and empty in your xml.
You only may set GetChanges to 1 or live it empty (which is by default = 1) in any consequential sync request, not in initial sync request.

Resources