Author: sumedha
Date: Wed Nov 12 12:14:03 2008
New Revision: 713490
URL: http://svn.apache.org/viewvc?rev=713490&view=rev
Log:
more support for accepting request messages from IM clients & sending back the
responses. Now we have fully functional code to test this scenario. However
error handling needs to be improved. Committing with TODOs
Modified:
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/XMPPSender.java
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPConstants.java
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPPacketListener.java
Modified:
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/XMPPSender.java
URL:
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/XMPPSender.java?rev=713490&r1=713489&r2=713490&view=diff
==============================================================================
---
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/XMPPSender.java
(original)
+++
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/XMPPSender.java
Wed Nov 12 12:14:03 2008
@@ -19,16 +19,18 @@
package org.apache.axis2.transport.xmpp;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
+import javax.xml.namespace.QName;
+
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.client.Options;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.description.AxisMessage;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
@@ -44,8 +46,16 @@
import org.apache.axis2.transport.xmpp.util.XMPPServerCredentials;
import org.apache.axis2.transport.xmpp.util.XMPPUtils;
import org.apache.axis2.util.Utils;
+import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.ws.commons.schema.XmlSchemaAll;
+import org.apache.ws.commons.schema.XmlSchemaComplexType;
+import org.apache.ws.commons.schema.XmlSchemaElement;
+import org.apache.ws.commons.schema.XmlSchemaGroupBase;
+import org.apache.ws.commons.schema.XmlSchemaParticle;
+import org.apache.ws.commons.schema.XmlSchemaSequence;
+import org.apache.ws.commons.schema.XmlSchemaType;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ChatManager;
import org.jivesoftware.smack.XMPPConnection;
@@ -187,11 +197,31 @@
WSDL2Constants.MEP_URI_OUT_IN.equals(
msgCtx.getOperationContext().getAxisOperation().getMessageExchangePattern());
- OMElement msgElement = msgCtx.getEnvelope();
- String soapMessage = msgElement.toString();
//int endOfXMLDeclaration = soapMessage.indexOf("?>");
//String modifiedSOAPMessage =
soapMessage.substring(endOfXMLDeclaration+2);
- message.setBody(soapMessage);
+
+ OMElement msgElement;
+ String messageToBeSent = "";
+
+ //TODO : need to read from a constant
+
if("xmpp/text".equals(xmppOutTransportInfo.getContentType())){
+ //if request is received from a chat client,
whole soap envelope
+ //should not be sent.
+ OMElement soapBodyEle =
msgCtx.getEnvelope().getBody();
+ OMElement responseEle =
soapBodyEle.getFirstElement();
+ if(responseEle != null){
+ msgElement =
responseEle.getFirstElement();
+ }else{
+ msgElement = responseEle;
+ }
+ }else{
+ //if request received from a ws client whole
soap envelope
+ //must be sent.
+ msgElement = msgCtx.getEnvelope();
+ }
+ messageToBeSent = msgElement.toString();
+ message.setBody(messageToBeSent);
+
XMPPClientSidePacketListener
xmppClientSidePacketListener = null;
if(waitForResponse && !msgCtx.isServerSide()){
@@ -236,22 +266,21 @@
Object obj = msgCtx.getProperty(XMPPConstants.MESSAGE_FROM_CHAT);
if(obj != null){
String message = (String)obj;
- String response = "";
- if(("help".compareToIgnoreCase(message.trim()) == 0)
- || "?".equals(message)){
- response = prepareHelpTextForChat();
- }else if("listServices".equals(message.trim())){
- response = prepareServicesList(msgCtx);
- }else if (message.trim().startsWith("getOperations")){
- response = prepareOperationList(msgCtx,message);
+ String response = "";
+
+ if(message.trim().startsWith("help")){
+ response = prepareHelpTextForChat();
+ }else if(message.trim().startsWith("listServices")){
+ response = prepareServicesList(msgCtx);
+ }else if (message.trim().startsWith("getOperations")){
+ response = prepareOperationList(msgCtx,message);
}else{
//TODO add support for more help commands
}
- sendChatMessage(msgCtx,response);
+ sendChatMessage(msgCtx,response);
}
- }
-
-
+ }
+
/**
* Prepares a list of service names deployed in current runtime
* @param msgCtx
@@ -272,13 +301,7 @@
int index = 1;
while(itrOperations.hasNext()){
AxisOperation operation =
(AxisOperation)itrOperations.next();
- //ArrayList params = operation.getParameters();
- //Iterator itrParams = params.iterator();
- String parameterList = "";
- //while(itrParams.hasNext()){
- // Parameter param = (Parameter)
itrParams.next();
- // parameterList = param.getName()+",";
- //}
+ String parameterList =
getParameterListForOperation(operation);
sb.append(index
+"."+operation.getName().getLocalPart()+"("+parameterList+")"+"\n");
index++;
}
@@ -289,6 +312,47 @@
return sb.toString();
}
+ /**
+ * Retrieves list of parameter names & their type for a given operation
+ * @param operation
+ */
+ private static String getParameterListForOperation(AxisOperation
operation) {
+ //Logic copied from BuilderUtil.buildsoapMessage(...)
+ StringBuffer paramList = new StringBuffer();
+ AxisMessage axisMessage =
+ operation.getMessage(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
+ XmlSchemaElement xmlSchemaElement =
axisMessage.getSchemaElement();
+ if(xmlSchemaElement != null){
+ XmlSchemaType schemaType = xmlSchemaElement.getSchemaType();
+ if (schemaType instanceof XmlSchemaComplexType) {
+ XmlSchemaComplexType complexType =
((XmlSchemaComplexType)schemaType);
+ XmlSchemaParticle particle = complexType.getParticle();
+ if (particle instanceof XmlSchemaSequence || particle
instanceof XmlSchemaAll) {
+ XmlSchemaGroupBase xmlSchemaGroupBase =
(XmlSchemaGroupBase)particle;
+ Iterator iterator =
xmlSchemaGroupBase.getItems().getIterator();
+
+ while (iterator.hasNext()) {
+ XmlSchemaElement innerElement =
(XmlSchemaElement)iterator.next();
+ QName qName = innerElement.getQName();
+ if (qName == null &&
innerElement.getSchemaTypeName()
+
.equals(org.apache.ws.commons.schema.constants.Constants.XSD_ANYTYPE)) {
+ break;
+ }
+ long minOccurs = innerElement.getMinOccurs();
+ boolean nillable = innerElement.isNillable();
+ String name =
+ qName != null ? qName.getLocalPart() :
innerElement.getName();
+ String type =
innerElement.getSchemaTypeName().toString();
+ paramList.append(","+type +" " +name);
+ }
+ }
+ }
+ }
+ //remove first ","
+ String list = paramList.toString();
+ return list.replaceFirst(",", "");
+ }
+
/**
* Prepares a list of service names deployed in current runtime
Modified:
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPConstants.java
URL:
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPConstants.java?rev=713490&r1=713489&r2=713490&view=diff
==============================================================================
---
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPConstants.java
(original)
+++
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPConstants.java
Wed Nov 12 12:14:03 2008
@@ -49,5 +49,5 @@
//This is set to true, if a request message is sent through XMPPSender
//Used to distinguish messages coming from chat clients.
public static final String CONTAINS_SOAP_ENVELOPE =
"transport.xmpp.containsSOAPEnvelope";
- public static final String MESSAGE_FROM_CHAT =
"transport.xmpp.message.from.chat";
+ public static final String MESSAGE_FROM_CHAT =
"transport.xmpp.message.from.chat";
}
Modified:
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPPacketListener.java
URL:
http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPPacketListener.java?rev=713490&r1=713489&r2=713490&view=diff
==============================================================================
---
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPPacketListener.java
(original)
+++
webservices/commons/trunk/modules/transport/modules/xmpp/src/org/apache/axis2/transport/xmpp/util/XMPPPacketListener.java
Wed Nov 12 12:14:03 2008
@@ -19,13 +19,26 @@
package org.apache.axis2.transport.xmpp.util;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.StringTokenizer;
+import java.util.concurrent.Executor;
+
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.stream.XMLStreamException;
+
import org.apache.axiom.om.OMException;
import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axiom.soap.SOAPFactory;
+import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
+import org.apache.axis2.builder.BuilderUtil;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
+import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.TransportInDescription;
import org.apache.axis2.description.TransportOutDescription;
@@ -33,6 +46,7 @@
import org.apache.axis2.transport.TransportUtils;
import org.apache.axis2.transport.xmpp.XMPPSender;
import org.apache.axis2.util.MessageContextBuilder;
+import org.apache.axis2.util.MultipleEntryHashMap;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -40,13 +54,6 @@
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
-import javax.xml.parsers.FactoryConfigurationError;
-import javax.xml.stream.XMLStreamException;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.concurrent.Executor;
-
public class XMPPPacketListener implements PacketListener {
private static final Log log =
LogFactory.getLog(XMPPPacketListener.class);
private XMPPConnectionFactory xmppConnectionFactory = null;
@@ -166,16 +173,21 @@
}
InputStream inputStream = new
ByteArrayInputStream(messageBody.getBytes());
- SOAPEnvelope envelope;
+ SOAPEnvelope envelope = null;
try {
Object obj =
message.getProperty(XMPPConstants.CONTAINS_SOAP_ENVELOPE);
if(obj != null && ((Boolean)obj).booleanValue()){
envelope =
TransportUtils.createSOAPMessage(msgContext, inputStream, "text/xml");
- msgContext.setEnvelope(envelope);
msgContext.setProperty(XMPPConstants.CONTAINS_SOAP_ENVELOPE, new Boolean(true));
}else{
- //A text message has been received from a chat
client, send it along with message context
-
msgContext.setProperty(XMPPConstants.MESSAGE_FROM_CHAT, messageBody);
+ //A text message has been received from a chat
client
+ //This message could either be a service call
or a help command
+
if(!(messageContainsCommandsFromChat(messageBody,msgContext))){
+ envelope =
createSOAPEnvelopeForRawMessage(msgContext, messageBody);
+ }
+ }
+ if(envelope != null){
+ msgContext.setEnvelope(envelope);
}
}catch (OMException e) {
log.error(logMsg, e);
@@ -192,6 +204,94 @@
}
}
+ /**
+ * In the direct chat client scenario, client can send commands &
retrieve details
+ * on available services, operations,etc. This method checks if a
client has sent
+ * such command. Only limited set of commands are available as of now.
+ * @param message
+ * @param msgContext
+ * @return
+ */
+ private boolean messageContainsCommandsFromChat(String
message,MessageContext msgContext){
+ boolean containsKnownCommand = false;
+ if(message.trim().startsWith("help")){
+ containsKnownCommand = true;
+ }else if(message.trim().startsWith("listServices")){
+ containsKnownCommand = true;
+ }else if (message.trim().startsWith("getOperations")){
+ containsKnownCommand = true;
+ }
+
+ if(containsKnownCommand){
+
msgContext.setProperty(XMPPConstants.MESSAGE_FROM_CHAT,message.trim());
+ }
+ return containsKnownCommand;
+ }
+
+ /**
+ * Creates a SOAP envelope using details found in chat message.
+ * @param msgCtx
+ * @param chatMessage
+ * @return
+ */
+ private SOAPEnvelope createSOAPEnvelopeForRawMessage(MessageContext
msgCtx,String chatMessage)
+ throws AxisFault{
+ //TODO : need to add error handling logic
+ String callRemoved = chatMessage.replaceFirst("call", "");
+ //extract Service name
+ String serviceName = callRemoved.trim().substring(0,
callRemoved.indexOf(":")-1);
+ String operationName =
callRemoved.trim().substring(callRemoved.indexOf(":"),
callRemoved.indexOf("(")-1);
+
+ //Extract parameters from IM message
+ String parameterList =
callRemoved.trim().substring(callRemoved.indexOf("("),callRemoved.trim().length()-1);
+ StringTokenizer st = new StringTokenizer(parameterList,",");
+ MultipleEntryHashMap parameterMap = new MultipleEntryHashMap();
+ while(st.hasMoreTokens()){
+ String token = st.nextToken();
+ String name = token.substring(0, token.indexOf("="));
+ String value = token.substring(token.indexOf("=")+1);
+ parameterMap.put(name, value);
+ }
+
+ SOAPEnvelope envelope = null;
+ try {
+
msgCtx.setProperty(XMPPConstants.CONTAINS_SOAP_ENVELOPE, new Boolean(true));
+ if(serviceName != null && serviceName.trim().length() >
0){
+ AxisService axisService =
msgCtx.getConfigurationContext().getAxisConfiguration().getService(serviceName);
+ msgCtx.setAxisService(axisService);
+
+ AxisOperation axisOperation =
axisService.getOperationBySOAPAction("urn:"+operationName);
+ if(axisOperation != null){
+ msgCtx.setAxisOperation(axisOperation);
+ }
+ }
+
+ if(operationName != null &&
operationName.trim().length() > 0){
+ msgCtx.setSoapAction("urn:"+operationName);
+ }
+
+ XMPPOutTransportInfo xmppOutTransportInfo =
(XMPPOutTransportInfo)msgCtx.getProperty(
+
org.apache.axis2.Constants.OUT_TRANSPORT_INFO);
+ //This should be only set for messages received via
chat.
+ //TODO : need to read from a constant
+ xmppOutTransportInfo.setContentType("xmpp/text");
+
+ msgCtx.setServerSide(true);
+
+ //TODO : need to support SOAP12 as well
+ SOAPFactory soapFactory = new SOAP11Factory();
+ envelope = BuilderUtil.buildsoapMessage(msgCtx,
parameterMap,
+ soapFactory);
+ //TODO : improve error handling & messages
+ } catch (AxisFault e) {
+ throw new AxisFault(e.getMessage());
+ } catch (OMException e) {
+ throw new AxisFault(e.getMessage());
+ } catch (FactoryConfigurationError e) {
+ throw new AxisFault(e.getMessage());
+ }
+ return envelope;
+ }
/**
* The actual Runnable Worker implementation which will process the
@@ -215,7 +315,7 @@
AxisEngine.receive(msgCtx);
}
}else{
- //Send a text reply message to chat
client
+ //Send a text reply message to command
received from chat client
XMPPSender.processChatMessage(msgCtx);
}
} catch (AxisFault e) {
@@ -232,4 +332,4 @@
}
}
}
-}
+}
\ No newline at end of file