Complex non XML/String Transforms

Latest response

Hello,

Still learning, please overlook some of my newbie-'isms....

Here is my scenario:
Trying to use Switchyard Camel Netty service binding to provide a connector to a legacy C++ Socket based messaging system. I've been successful in using standalone Camel to create a netty route using a decoder to retrieve the byte[] and generate my POJO:

public class MessageDecoder extends FrameDecoder {
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel,
ChannelBuffer buffer) throws Exception {

// buffer.skipBytes(4);//(3)
byte[] decoded = new byte[buffer.readableBytes()];
buffer.readBytes(decoded);
String msg = new String(decoded);// (4)
System.out.println("Decoded msg: " + msg);
TrainnerCommon aTrainnerCommon = new TrainnerCommon();
aTrainnerCommon.setMsgID(1234);
aTrainnerCommon.setMsg(msg.getBytes());
System.out.println("Trainer Object: " + aTrainnerCommon);
return aTrainnerCommon;
}

}

For the life of me, I cannot figure out how to produce this into Fuse Service Works using Switchyard. I seems like 'natively' all the bindings and their transforms are expecting String and formatted XML 'payloads'!?! Found some examples using what appears to be just Fuse using an @Converter annotation, ie:

@Converter
public IFacadeMessage toIFacadeMessage(byte[] data, Exchange exchange) {
...
}

But cannot figure out how, via Switchyard to do the same as Fuse or standalone Camel?!?

To do this type of binding and service am I going to have to use a Camel URI using decoder??

Any help is very appreciated!

===========================
2015-02-19
Adding Screen grab of Debugger variables in the Composer

Attachments

Responses

More digging has brought me to: org.switchyard.component.camel.common.composer.CamelMessageComposer

Found examples such as quickstarts.soap.binding.rpc... hopefully these will start shedding some light.

How are you going with this, John?

Howdy! Such interesting timing...

So been looking at: https://github.com/apodhrad/switchyard-examples/blob/master/bean-http-composer/src/main/java/org/apodhrad/switchyard/example/bean_http_composer/HttpPersonComposer.java

And trying to modify to use with CamelMessageComposer. It seem like all I should have to do is (SnmpMessage) source.getMessage() but each time I'm getting null.

Then tried using the context to to mapFrom:
final Message message = exchange.createMessage();
getContextMapper().mapFrom(source, exchange.getContext(message));

Still null...

What doesn't make since, is when in debug mode, I can see source has an _Message of type SnmpMessage. Seems like so close... but missing something fundamental...

Adding some attachments...

John, I've asked some of my colleagues for some assistance with this. Please keep me updated with any progression from your end.

Well... (I know, a deep subject)... a good nights sleep I guess is all it took... or the whiskey? ;-) This morning, I'm progressing and past my null issue. In the compose, I'm simply doing the following and it's fine:
public Message compose(CamelBindingData source, Exchange exchange)
throws Exception {
Object sourceObject = null;
SnmpMessage anSnmpMessage = null;
SysmanSNMP sysmanObject = null;
sourceObject = source.getMessage();
if (sourceObject != null) {
System.out.println("Composer Content: sourceObject is NOT null! " + source.getMessage());
if (sourceObject instanceof SnmpMessage) {
anSnmpMessage = (SnmpMessage) sourceObject;
System.out.println("Is instance of SnmpMessage");
if (anSnmpMessage != null) { .....

I'm getting a properly type casted SnmpMessage and making it out of the compose method with a transformed object!

Thanks for your patience and help!!

Now on to getting my Routing working ;-)

Thanks again!

I take it back... I know what I did differently... I added a change to the switchyard.xml!
Was reading this blog: http://unpoucode.blogspot.com.es/2014/10/message-composers-in-switchyard.html

And added the .* to the Regular expression Includes section of Message Composer. Therefore, the switchyard.xml service xml node looks like:

<sca:interface.java interface="org.switchyard.quickstarts.rules.camel.cbr.RoutingService"/>
<camel_1:binding.uri configURI="snmp:localhost:162?protocol=udp&type=TRAP&snmpVersion=0">



</camel_1:binding.uri>

Hi John,

Glad to hear of your progress. Jorge Morales is a great consultant here at Red Hat. I will see that we add this information of his to our product documentation. Thank you for helping to identify this gap in our content.

Regards,
Ben

Howdy Ya'll... been a little bit and some good water under the bridge ;-) But need to reach out and see if anyone has more 'best practices' or better ideas than the one's I've uncovered! LOL!

To continue on this thread, I'm now looking about how to compose and decompose byte array's received from netty binding from a Windows C++ socket client.

Let's go with a simple case first:
Given the following C++ implemented structure:

* typedef struct _WSTHEADER {
 WORD wMsgID;
 WORD wByteCount;
 } WSTHEADER, *PWSTHEADER;

When received via netty into my composer class I do the following:

source.getMessage()
...
if (source instanceof org.apache.camel.Message) {
        LOGGER.info("Received org.apache.camel.Message");
        LOGGER.info("Here is the body: "
            + ((org.apache.camel.Message) source).getBody());

        try {
        byteArrayMessage = ((org.apache.camel.Message) source)
            .getBody(byte[].class);

When looking at the byte array, you get the following:

Byte array = [7, 3, 50, 0]

So right off, there is a byte swap issue, so I ask my C++ team to do the following:

WTSTHEADER.wByteCount = htons(50);
WTSTHEADER.wMsgID     = htons(775);

Then I receive via netty:

[3,7,0,50]

And I process it, don't laugh too much, like this:

public static Header getHeader(byte[] aByteArray) {
    Header aHeader = new Header();

    for (int x = 0; x < aByteArray.length; x += 2) {
        byte[] tmBA = new byte[2];
        tmBA[0] = aByteArray[x];
        tmBA[1] = aByteArray[x + 1];
        if (x == 0) {
        aHeader.setMsgID(fromBinaryStringEncodedByteArray(tmBA));
        } else {
        aWSTHeader.setByteCount(fromBinaryStringEncodedByteArray(tmBA));
        return aHeader;
        }
    }

    return aWSTHeader;
    }

    public static int fromBinaryStringEncodedByteArray(byte[] aByteArray) {
    BigInteger bi = new BigInteger(aByteArray);

    return Integer.parseInt(bi.toString(2), 2);
    }

So end game is I have to know the byte layout of each message and then depending on windows WORD or DWORD, pull 4 and 8 byte chunks and convert into ints from a Binary String... All good, under need to have an Interface control doc and know the formats, but what about all this hoping about with byte swapping and bytes to BigInteger math... etc etc etc

Are there other utils or netty configurations I'm missing that would allow for a 'cleaner' composition and decomp of Windows structures over socket???

Thanks!!!!