13 Replies Latest reply on Jul 5, 2013 9:10 PM by Dustin Barlow

    Correct way to set correlationKey in a SOAP Header?

    Dustin Barlow Newbie

      Does anyone have an example SOAP request that provides a correlationKey in a SOAP header?  I want to confirm that I have the correct syntax.

       

      I have been successful in using the processInstanceId like this:

       

      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.foo.switchyard.myproject:foo-switchyard-myproject:1.0">
         <soapenv:Header>
                <processInstanceId xmlns="urn:switchyard-component-bpm:bpm:1.0">1</processInstanceId>
         </soapenv:Header>
         <soapenv:Body>
           ...
         </soapenv:Body>
      </soapenv:Envelope>
      

       

      I then tried setting correlationKey this way for the BPM START_PROCESS request:

       

      <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.foo.switchyard.myproject:foo-switchyard-myproject:1.0">
         <soapenv:Header>
                <correlationKey xmlns="urn:switchyard-component-bpm:bpm:1.0">123456789</correlationKey>
         </soapenv:Header>
         <soapenv:Body>
         ...
         </soapenv:Body>
      </soapenv:Envelope>
      

       

      However, subsequent BPM SIGNAL_EVENT SOAP requests where I use that same correlationKey in the SOAP header does not seem to work in triggering the correct process instance.  Instead, every existing BPM process gets triggered.

       

      I am using switchyard-as7-0.8.

        • 1. Re: Correct way to set correlationKey in a SOAP Header?
          David Ward Master

          Can you please attach a sample project that exhibits this behavior so I can debug it?  I will create a jira and fix it if there is a bug, verifying it works with the app.  Otherwise, I'll let you know what needs to change.

          • 2. Re: Correct way to set correlationKey in a SOAP Header?
            Dustin Barlow Newbie

            Attached is a small project that consists of a BPM component that has one Bean that acknowledges the message for a START_PROCESS and a second Bean that is triggered on a SIGNAL_EVENT.  There is a SOAP binding for both the "submit" and the "finish" process.

             

            First I submitted this:

             

            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.example.switchyard:switchyard-bpm-example:1.0">
               <soapenv:Header>
                      <correlationKey xmlns="urn:switchyard-component-bpm:bpm:1.0">1234</correlationKey>
               </soapenv:Header>
               <soapenv:Body>
                  <urn:submit>
                     <request>
                        <name>Dustin</name>
                        <requestType>FOO</requestType>
                     </request>
                  </urn:submit>
               </soapenv:Body>
            </soapenv:Envelope>
            
            

             

            Which results in this:

             

            20:12:35,004 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) ********* Acknowledge, contentInput: com.example.switchyard.bpm.Request@35844fae name: Dustin, type: FOO, hash: 897863598
            

             

            Second, I submitted this:

             

            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.example.switchyard:switchyard-bpm-example:1.0">
               <soapenv:Header>
                      <correlationKey xmlns="urn:switchyard-component-bpm:bpm:1.0">5678</correlationKey>
               </soapenv:Header>
               <soapenv:Body>
                  <urn:submit>
                     <request>
                        <name>David</name>
                        <requestType>BOO</requestType>
                     </request>
                  </urn:submit>
               </soapenv:Body>
            </soapenv:Envelope>
            

             

            Which results in this:

             

            20:14:18,306 INFO  [stdout] (http-localhost-127.0.0.1-8080-1) ********* Acknowledge, contentInput: com.example.switchyard.bpm.Request@7b629209 name: David, type: BOO, hash: 2070057481
            

             

            Third, I submitted this to trigger the finish of the first submission:

             

            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:com.example.switchyard:switchyard-bpm-example:1.0">
               <soapenv:Header>
                      <correlationKey xmlns="urn:switchyard-component-bpm:bpm:1.0">1234</correlationKey>
               </soapenv:Header>
               <soapenv:Body>
                  <urn:finish/>
               </soapenv:Body>
            </soapenv:Envelope>
            

             

            Which results in this:

             

            20:15:47,676 INFO  [stdout] (default-workqueue-1) ********* Received Finish Event, contentInput: com.example.switchyard.bpm.Request@35844fae hash: 897863598
            20:15:47,678 INFO  [stdout] (default-workqueue-1) ********* Finish, contentInput: com.example.switchyard.bpm.Request@35844fae name: Dustin, type: FOO, hash: 897863598
            20:15:47,680 INFO  [stdout] (default-workqueue-1) ********* Received Finish Event, contentInput: com.example.switchyard.bpm.Request@7b629209 hash: 2070057481
            20:15:47,682 INFO  [stdout] (default-workqueue-1) ********* Finish, contentInput: com.example.switchyard.bpm.Request@7b629209 name: David, type: BOO, hash: 2070057481
            

             

            You'll see that both processes were triggered which is similar behavior to when you don't provide a processInstanceId.  All existing processes are notified.

             

            The correlationKey does make it into Switchyard as seen here:

             

            ------- Begin Message Trace -------
            Service -> {urn:com.example.switchyard:switchyard-bpm-example:1.0}ProcessServicePortType
            Operation -> submit
            Phase -> IN
            State -> OK
            Exchange Context -> 
            Message Context -> 
                      {urn:switchyard-component-bpm:bpm:1.0}correlationKey : 1234
                      org.switchyard.contentType : {urn:com.example.switchyard:switchyard-bpm-example:1.0}submit
                      Accept : text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
                      org.switchyard.messageId : afba8f12-2bcc-40d2-b53c-37461d5a23f6
                      org.switchyard.soap.messageName : submit
            Message Content -> 
            <?xml version="1.0" encoding="UTF-8"?><request>
                        <name>Dustin</name>
                        <requestType>FOO</requestType>
                     </request>
            ------ End Message Trace -------
            
            

             

            However, it is not seen in any of the other traces after the initial one.

            • 3. Re: Correct way to set correlationKey in a SOAP Header?
              David Ward Master

              Thanks, Dustin.  I am technically on PTO today (Thursday) and tomorrow, but will look at this later tonight from my hotel.

              • 4. Re: Correct way to set correlationKey in a SOAP Header?
                David Ward Master

                Dustin,

                 

                Okay, I was able to take a look at this.  The problem is that the correlationKey context property is not making it to the BPMExchangeHandler.  I believe the reason for this is that you defined a <soap:contextMapper> element in your switchyard.xml for the soap binding, but didn't specify an includes=".*" attribute.  Which basically means all properties get excluded (filtered out).  The effect of this is that the BPM component, not being handed a correlationKey, thinks that you want to signal all process instances.

                 

                So, what you should try:

                1. Add an includes=".*"  to your soap:contextMapper.  (I think soapHeadersType="VALUE" is fine for this - sorry it's late here and my brain ain't at 100% - but if it's not, try "DOM".)
                2. Let me know how that works!

                 

                What I have as a follow-up to this;

                1. Write documentation that makes sure people understand the relationship between expected bpm properties and the contextMapper behavior.
                2. Handle the situations of "signal all prcoess instances with this event id" (a valid usecase!) vs. "oops I tried signaling with a correlationKey and it didn't work - dont' default to all process instances!!!"
                3. I think I also found a possible bug in the KnowledgeExchangeHandler wrt looking at the EXCHANGE scope for certain BPM variables vs. MESSAGE scope.  In my tests, it worked either way, which I don't quite understand right now, but I want to clean this up.
                4. Enhance the test service Invoker to set context properties in a fluid manner.  I actually did this locally to figure out your issue, so I can do this along with the above.

                 

                I am unavailable most of tomorrow, but should be available to work this out this weekend or by very early next week.

                 

                Thanks,

                David

                • 5. Re: Correct way to set correlationKey in a SOAP Header?
                  Dustin Barlow Newbie

                  David,

                   

                  First off, thank you for looking at this while you're on PTO.  Hopefully your boss sees this and your extra effort bodes well for you on your next review.

                   

                  I tried adding the includes=".*" to the soap:contextMapper element, but I get the same behavior of all the existing process instances firing.  I also tried setting soapHeadersType="DOM" as well with the same results.

                   

                  Do you have any other ideas of things I could try?  In your testing, did you actually use SOAP calls and got it to work, or did you do it via the service invoker API?


                  I also wanted to point out too that with the exception of having to manually set the id for the BPM signal in the switchyard.xml, the rest of that file was all generated by the Eclipse tooling, including the contextMapper portion.

                   

                  I noticed that when you first add a SOAP binding to the promoted service, the tooling doesn't always put the <soap:contextMapper includes=".*" soapHeadersType="VALUE"/> element in the generated SOAP binding XML.  This, of course, results in no processInstanceId being returned in the SOAP header.  I guess that is understandable for the tooling not to add that by default since it is really only requried by BPM or Rules for correlation.

                   

                  Here's what is odd though.  If I go back into the service binding property editor, Eclipse shows the switchyard.xml as having being modified again even though I didn't change anything.  If I view the switchyard.xml source, it is then that the <soap:contextMapper> element is magically added.  Looks to be an inconsistency of what "default" is in the add binding wizard vs. the property editor in the tooling.

                   

                  Regarding the behavior of all process instances firing and changing this behavior, I tend to favor explicit vs. implicit when it comes to a "trigger all" scenario.  If someone wants to signal all currently running instances, then I would think you'd want the interface to not imply that by the lack of any data in the header or the lack of what was passed in not matching any existing processes.  The default behaviour could just be to not notify anything, similar to how it behaves if you pass in a non-existing processInstanceId.  That seems to generally be a safer and possibly more predictable approach.

                  • 6. Re: Correct way to set correlationKey in a SOAP Header?
                    David Ward Master

                    Hi Dustin,

                     

                    I originally had only tested using the service invoker API (which, BTW, I've added fluid ways to set context properties on it, per your suggestion).  When I tested with soapui, the problem surfaced, which was related to the bug I mentioned above regarding how the exchange handler is accessing properties.

                     

                    ANYWHO, I've fixed it per this jira: SWITCHYARD-1579

                     

                    I added a bunch of junit testing in switchyard itself, however I also tested using your application, both via junit and soapui.  I now currectly only see one process instance get signaled (even though 2 process instances exist) in both cases:

                     

                    00:53:55,440 INFO  [stdout] (http-/127.0.0.1:8080-1) ********* Acknowledge, contentInput: com.example.switchyard.bpm.Request@92abdf name: Dustin, type: FOO, hash: 9612255
                    00:54:09,830 INFO  [stdout] (http-/127.0.0.1:8080-1) ********* Acknowledge, contentInput: com.example.switchyard.bpm.Request@1f24a78 name: David, type: BAR, hash: 32655992
                    00:55:15,978 INFO  [stdout] (default-workqueue-1) ********* Received Finish Event, contentInput: com.example.switchyard.bpm.Request@92abdf hash: 9612255
                    00:55:15,979 INFO  [stdout] (default-workqueue-1) ********* Finish, contentInput: com.example.switchyard.bpm.Request@92abdf name: Dustin, type: FOO, hash: 9612255
                    

                     

                    I did have to modify your application, however, per configuration changes in the bpm component between 0.8.0.Final and 1.0.0-SNAPSHOT.  This affected the bpmn file and the switchyard.xml file.  I will attach the modified project here that works with 1.0.0-SNAPSHOT, but I will also copy/paste some sections of interest here:

                     

                    The soap binding looks like this:

                     

                          <soap:binding.soap>
                            <soap:contextMapper includes=".*"/>
                            <soap:messageComposer unwrapped="true"/>
                            <soap:wsdl>ProcessService.wsdl</soap:wsdl>
                            <soap:contextPath>switchyard-bpm-example</soap:contextPath>
                          </soap:binding.soap>
                    

                     

                    The bpm component looks like this:

                     

                          <bpm:implementation.bpm persistent="false" processId="ProcessService">
                            <bpm:manifest>
                              <bpm:resources>
                                <bpm:resource location="META-INF/ProcessServiceComponent.bpmn" type="BPMN2"/>
                              </bpm:resources>
                            </bpm:manifest>
                            <bpm:operations>
                              <bpm:operation name="submit" type="START_PROCESS">
                                <bpm:inputs>
                                  <bpm:input from="message.content" to="contentInput"/>
                                </bpm:inputs>
                                <bpm:outputs>
                                  <bpm:output from="contentOutput" to="message.content"/>
                                </bpm:outputs>
                              </bpm:operation>
                              <bpm:operation eventId="FinishSignal" name="finish" type="SIGNAL_EVENT">
                                <bpm:inputs>
                                  <bpm:input from="message.content" to="contentInput"/>
                                </bpm:inputs>
                              </bpm:operation>
                              <bpm:operation eventId="FinishSignal" name="finishAll" type="SIGNAL_EVENT_ALL">
                                <bpm:inputs>
                                  <bpm:input from="message.content" to="contentInput"/>
                                </bpm:inputs>
                              </bpm:operation>
                            </bpm:operations>
                          </bpm:implementation.bpm>
                    

                     

                    Notice that "actions" are now "operations".  Also notice how much easier the from/to is than the old expression/variable.  Finally, notice that I added a SIGNAL_EVENT_ALL to be specific (vs. implicit), per your good suggestion.

                     

                    Here is the modified junit test that shows the new fluid Invoker api to set context properties:

                     

                    import static org.switchyard.component.bpm.BPMConstants.CORRELATION_KEY_PROPERTY;
                    
                    public void testSubmit() throws Exception {
                    
                            Request submit_1 = new Request();
                            submit_1.setName("Dustin");
                            submit_1.setRequestType("FOO");
                            RequestAck result_1 = service.operation("submit").property(CORRELATION_KEY_PROPERTY, "1234").sendInOut(submit_1).getContent(RequestAck.class);
                            Assert.assertTrue(result_1.isAccepted());
                    
                            Request submit_2 = new Request();
                            submit_2.setName("David");
                            submit_2.setRequestType("BOO");
                            RequestAck result_2 = service.operation("submit").property(CORRELATION_KEY_PROPERTY, "5678").sendInOut(submit_2).getContent(RequestAck.class);
                            Assert.assertTrue(result_2.isAccepted());
                    
                            Object finish = null;
                            service.operation("finish").property(CORRELATION_KEY_PROPERTY, "1234").sendInOnly(finish);
                            //service.operation("finish").property(CORRELATION_KEY_PROPERTY, "5678").sendInOnly(finish);
                            //service.operation("finishAll").sendInOnly(finish);
                    
                    }
                    

                     

                    I'm not going to include the bpmn2 changes here, but there were some SwitchYard Service Task changes, that are already reflected in the latest version of the SwitchYard Eclipse Tooling.

                     

                    Thanks again for bringing this to my attention, and for your patience while I fix it.

                     

                    Best,

                    David

                    • 8. Re: Correct way to set correlationKey in a SOAP Header?
                      Dustin Barlow Newbie

                      Hi Dave,

                       

                      This looks fantastic!  I will give it a try once I get a chance to upgrade my local environment to the 1.0-SNAPSHOT release.  I'm not looking forward to trying to switch the Eclipse tooling from 0.8-FINAL to 1.0-SNAPSHOT.  Upgrading always seems to be more painful then it should be when it comes to Eclipse plugins.

                       

                      One question about the Invoker API change you made.  How would set multiple properties?  I don't know if this would ever be a requirement or not, but just curious.

                       

                      I'll give it all a spin and report back if I find any issues.  Glad I could help in someway and thank you for the quick turn around on this fix.

                       

                      Dustin

                      • 9. Re: Correct way to set correlationKey in a SOAP Header?
                        David Ward Master

                        I hear ya' about upgrading. Regarding the Invoker API change: it's a fluent api, so just invoke the property method multiple times.  I didn't add a bulk add all these props all at once, as I'm thinking that won't be a common need.

                        • 10. Re: Correct way to set correlationKey in a SOAP Header?
                          Dustin Barlow Newbie

                          Have you considered adding an "abort all" operation type as well? 

                           

                          Implementing a SIGNAL_EVENT_ALL a certain way might work to abort everything, but I'm not sure from within a single BPM process instance how one would programmatically iterate over existing processes and call abort on them.

                          • 11. Re: Correct way to set correlationKey in a SOAP Header?
                            David Ward Master

                            I have not considered an "abort all" operation type.  Take a look at org.kie.api.runtime.process.ProcessRuntime.  It supports signalEvent to one or all, but abortProcessInstance is only to one.  I'm trying to keep to what KIE gives me from an interface perspective.

                            • 12. Re: Correct way to set correlationKey in a SOAP Header?
                              David Ward Master

                              Dustin, you might be interested in this, which will not make it in 1.0, but I'd like to see it soon after: SWITCHYARD-1585

                              • 13. Re: Correct way to set correlationKey in a SOAP Header?
                                Dustin Barlow Newbie

                                Thanks for the link.  I agree that it would be nice to be able to set the correlationKey and the processInstanceId in the message payload especially in cases where bindings don't support a header type semantic. 

                                 

                                This also could mean that the client of the service can implement correlationKey logic in a non service binding specific way.  In other words, you don't need the client to know that they have to also create a custom SOAP header.