Announcement Announcement Module
Collapse
No announcement yet.
How to create SOAPFault Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to create SOAPFault

    I have tried many approaches to try to get this to work but I can not figure out how to send back a SOAPFault with a detail section when an Exception occurs.

    This project receives a message on a int-ws:inbound-gateway "wsModifyKeys", saves the ReplyChannel into a map "snrHeaderSaver" and routes the message to a int-ip:tcp-outbound-channel-adapter channel "tcpSNROutbound" via the channel "tcpSNRSend".

    Once the response is received on the channel "tcpSNRReceive" it is routed back by "tcpInputRouter" based on the ContentType header back to the channel "modifyKeysResponseWithoutHeaderChannel" by the "resolveChannel" method.

    Then a header-enricher get the message, puts the replyChannel header back on on the message and sends it to the channel "modifyKeysResponseChannel".

    From there a bean called by the service-activator "modifyKeysResponseService" logs the message and checks the content-length.

    If the content-length of the message is 0 I need to return a SOAPFault. I can not figure out how to do that. If I throw an exception is goes back to the int-ip:tcp-outbound-channel-adapter and is logged as an exception in the server log file.

    This seems correct as this thread started at the tcp-inbound-channel-adapter so the exception will go up the call chain until it is thrown and not caught, thus it ends up in the server log file.

    I need the exception to go out the ws:inbound-gateway back to the calling web service client so they can see the fault.

    Here is the context and related code.

    Code:
    <int:channel id="tcpSNRSend"/>
    
    
    <!-- Out-bound message channel w/o ip_connection_id header -->
    <int:channel id="tcpSNRSendWithoutIpConnectionIdHeader" />
    
    <!-- This channel will allow multiple subscribers to receive a message from 
    	this channel -->
    <int:channel id="tcpSNRReceive">
    </int:channel>
    
    <!-- Routes messages using custom router -->
    <int:router ref="tcpInputRouter" 
    	    input-channel="tcpSNRReceive"
    	    method="resolveChannel" />
    
    <!-- Places ip_connection_id header back on message by trans-isd -->
    <int:header-enricher input-channel="tcpSNRSendWithoutIpConnectionIdHeader"
    		     output-channel="tcpSNRSend">
    	<int:header name="ip_connection_id" 
    	            method="computeValue" 
    		    ref="saveIpConnectionId" />
    </int:header-enricher>			    
    
    <int-ip:tcp-connection-factory id="cfSNRClient"
    	 		       type="client" 
    			       host="${snr_connection_ip_address}" 
    			       port="${snr_connection_port}"
    			       deserializer="connectionSerializeDeserialize"
    			       serializer="connectionSerializeDeserialize"
    			       single-use="false" />
    
    <int-ip:tcp-outbound-channel-adapter id="tcpSNROutbound" 
    					channel="tcpSNRSend" 
    					connection-factory="cfSNRClient" />
    
    <int-ip:tcp-inbound-channel-adapter id="tcpSNRInbound" 
    					channel="tcpSNRReceive"
    					connection-factory="cfSNRClient" />	
    					
    <int:channel id="modifyKeysOutputChannel"/>		
    <int:channel id="modifyKeysResponseChannel"/>
    									
    <int:header-enricher input-channel="tcpSNRSendWithoutIpConnectionIdHeader"
    					 output-channel="tcpSNRSend">
    	<int:header name="ip_connection_id" 
    		    method="computeValue" 
    		    ref="saveIpConnectionId" />
    </int:header-enricher>	
    
    <int:service-activator id="modifyKeysRequestService"
    		   input-channel="modifyKeysInputChannel" 
    		   output-channel="tcpSNRSendSaveHeader"
    		   ref="modifyKeysService" 
    		   method="modifyKeys"/>
    
    <int:service-activator id="modifyKeysResponseService"
    		   input-channel="modifyKeysResponseChannel" 
    		   output-channel="modifyKeysOutputChannel"
    		   ref="modifyKeysService" 
    		   method="modifyKeysResponse" />
    
    <int:channel id="tcpSNRSendSaveHeader" />
    
    <int:router ref="snrHeaderSaver" 
    	    input-channel="tcpSNRSendSaveHeader"
    	    method="saveChannel" />
    			
    <int:header-enricher input-channel="modifyKeysResponseWithoutHeaderChannel"
    					 output-channel="modifyKeysResponseChannel">
    	<int:header name="replyChannel" 
    			    method="computeValue" 
    			    ref="snrHeaderSaver" />
    </int:header-enricher>
    
    
    
    <int-ws:inbound-gateway id="wsModifyKeys"
    		request-channel="modifyKeysInputChannel" 
    		reply-channel="modifyKeysOutputChannel"
    		marshaller="xmlBeansMarshaller" 
    		unmarshaller="xmlBeansMarshaller" />	
    	
    <!-- Simple calls with a getter/setter -->
    <bean id="snrHeaderSaver" class="com.intrado.isg2.bl.SaveMessageChannelHeader" init-method="init"/>
    
    <bean id="modifyKeysService"
    	class="com.intrado.isg2.ws.server.modifykeys.impl.ModifyKeysServiceImpl">
    </bean>	
    
    
    public String saveChannel(Message<?> message) {
    		String payload = (String)message.getPayload();
    		
    		int first = payload.indexOf(ISG2Constants.TRANS_ID + ":");
    		int len = ISG2Constants.TRANS_ID.length();
    		int last = payload.indexOf("\r\n", first + len + 2);
    		String transId = payload.substring(first + len + 2, last);
    		MessageChannel messageChannel = (MessageChannel) message.getHeaders().getReplyChannel();
    		this.setHeader(transId, messageChannel);
    		
    		return "tcpSNRSend";
    }
    
    
    	
    	public String resolveChannel(Message<?> message) {
    	byte[] payload = (byte[]) message.getPayload();
    	ByteArrayInputStream bis = new ByteArrayInputStream(payload);
    	ObjectInputStream s;
    	EsmiMessage esmiMessage = null;
    	try {
    		s = new ObjectInputStream(bis);
    		esmiMessage = (EsmiMessage) s.readObject();
    		
    		HeaderGroup headerGroup = new HeaderGroup();		
    		headerGroup.setHeaders(esmiMessage.getHeaders());
    		String contentType = headerGroup.getFirstHeader("content-type").getValue();
    		String transactionId = headerGroup.getFirstHeader(ISG2Constants.TRANS_ID).getValue();
    		saveIpConnectionId.setIpConnectionId(transactionId, (String)message.getHeaders().get("ip_connection_id"));
    
    		if (contentType.compareTo(ISG2Constants.HEARTBEAT_MESSAGE) == 0) {
    			return "heartbeatChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.HEALTHREQUEST_MESSAGE) == 0) {
    			return "healthRequestChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.EISQUERY_MESSAGE) == 0) {
    			return "eisQueryChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.KEY_ASSOCIATION_MESSAGE) == 0) {
    			return "keyAssociationChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.HEALTH_RESPONSE_MESSAGE) == 0) {
    			return "heartbeatResponseChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.SOURCE_REGISTRATION_RESPONSE_MESSAGE) == 0) {
    			return "sourceRegResponseWithoutHeaderChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.SOURCE_DEREGISTRATION_RESPONSE_MESSAGE) == 0) {
    			return "sourceDeregResponseWithoutHeaderChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.SOURCE_REGISTRATION_STATUS_RESPONSE_MESSAGE) == 0) {
    			return "sourceRegStatusResponseWithoutHeaderChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.SENDINFORMATION_MESSAGE) == 0) {
    			return "sendInformationChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.MODIFYKEYSRESULT_MESSAGE) == 0) {
    			return "modifyKeysResponseWithoutHeaderChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.KEY_ASSOCIATION_GEOCODE_MESSAGE) == 0) {
    			return "ptolemyRequestChannel";
    		}
    		if (contentType.compareTo(ISG2Constants.DISCONNECT_NOTIFICATION_MESSAGE) == 0) {
    			return "disconnectNotificationChannel";
    		}
    	} catch (IOException e) {
    		logger.log(ISG2Event.ISG2_ERROR_29, EventMessage.getMessage(e.toString()), e);		
    	} catch (ClassNotFoundException e) {
    		logger.log(ISG2Event.ISG2_ERROR_30, EventMessage.getMessage(e.toString()), e);	
    	}
    	
    	return "";
    }
    Please give me a clue how to get a SOAPFault back to the web service caller.

  • #2
    I believe I figured this problem out. I added a error-channel to the tcp-inbound-channel-adapter that was catching the exception. I then put a transformer on the error channel. I am now able to return a SOAPFault to the calling web service.

    Code:
    <int-ip:tcp-inbound-channel-adapter id="tcpSNRInbound" 
    						channel="tcpSNRReceive"
    						error-channel="errorChannel"
    						connection-factory="cfSNRClient" />
    
    
    <int:transformer input-channel="errorChannel"
        				 output-channel="modifyKeysOutputChannel"
        				 expression="payload.failedMessage">
        </int:transformer>
    
    <bean id="endpointExceptionResolver"
        	        class="com.intrado.isg2.bl.MyServiceExceptionResolver">
                <property name="defaultFault" value="RECEIVER,Oops - Server Error Test" />
                <property name="exceptionMappings">
                    <value>
        	    com.intrado.isg2.bl.ServiceFaultException=SERVER,A server exception was encountered.
                    </value>		
           	   </property>
     	</bean>
    I hope this helps someone in the future.

    Comment


    • #3
      Nice! Glad you were able to figure it out - sorry we weren't able to respond earlier - many of us were traveling.

      Thanks for posting the solution.

      Comment


      • #4
        No problem Gary, compared to other forums you guys do a fantastic job answering our not so intelligent questions in a very responsible time. Keep up the good work. I REALLY like Spring Integration.

        Comment

        Working...
        X