Author: ngn
Date: Sat Jun 12 20:53:38 2010
New Revision: 954138

URL: http://svn.apache.org/viewvc?rev=954138&view=rev
Log:
Adding XML parsing to the BOSH implementation (by Bogdan Pistol) (VYSPER-207)

Added:
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
Modified:
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
    
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java

Modified: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java?rev=954138&r1=954137&r2=954138&view=diff
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
 (original)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshBackedSessionContext.java
 Sat Jun 12 20:53:38 2010
@@ -19,11 +19,9 @@
  */
 package org.apache.vysper.xmpp.extension.xep0124;
 
-import org.apache.mina.core.future.CloseFuture;
-import org.apache.mina.core.future.IoFuture;
-import org.apache.mina.core.future.IoFutureListener;
-import org.apache.mina.core.session.IoSession;
-import org.apache.vysper.mina.codec.StanzaWriteInfo;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.server.AbstractSessionContext;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
@@ -34,29 +32,32 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * connects MINA 2 frontend to the vysper backend through the Bosh protocol
+ * Keeps the session state
  *
  * @author The Apache MINA Project ([email protected])
  */
 public class BoshBackedSessionContext extends AbstractSessionContext implements
-        StanzaWriter, IoFutureListener {
+        StanzaWriter {
 
-    final Logger logger = LoggerFactory
+    private final Logger logger = LoggerFactory
             .getLogger(BoshBackedSessionContext.class);
 
-    private IoSession minaSession;
+    private final BoshDecoder boshDecoder;
 
-    private boolean openingStanzaWritten = false;
+    private HttpServletRequest httpRequest;
 
-    protected CloseFuture closeFuture;
+    private HttpServletResponse httpRespone;
 
+    /**
+     * Creates a new context for a session
+     * @param serverRuntimeContext
+     * @param boshHandler
+     */
     public BoshBackedSessionContext(ServerRuntimeContext serverRuntimeContext,
-            SessionStateHolder sessionStateHolder, IoSession minaSession) {
-        super(serverRuntimeContext, sessionStateHolder);
-        this.minaSession = minaSession;
-        closeFuture = minaSession.getCloseFuture();
-        closeFuture.addListener(this);
-        sessionStateHolder.setState(SessionState.INITIATED); // connection 
established
+            BoshHandler boshHandler) {
+        super(serverRuntimeContext, new SessionStateHolder());
+        sessionStateHolder.setState(SessionState.INITIATED);
+        boshDecoder = new BoshDecoder(boshHandler, this);
     }
 
     public StanzaWriter getResponseWriter() {
@@ -64,27 +65,54 @@ public class BoshBackedSessionContext ex
     }
 
     public void setIsReopeningXMLStream() {
-        openingStanzaWritten = false;
     }
 
     public void write(Stanza stanza) {
-        minaSession.write(new StanzaWriteInfo(stanza, !openingStanzaWritten));
-        openingStanzaWritten = true;
+        //        minaSession.write(new StanzaWriteInfo(stanza, 
!openingStanzaWritten));
     }
 
     public void close() {
         logger.info("session will be closed now");
-        closeFuture.setClosed();
-        minaSession.close(true);
     }
 
-    public void operationComplete(IoFuture ioFuture) {
-        // close future notification
-        logger.info("close future called");
+    public void switchToTLS() {
+        // BOSH cannot switch dynamically,
+        // SSL can be enabled/disabled in BoshEndpoint#setSSLEnabled()
     }
 
-    public void switchToTLS() {
-        // Bosh cannot switch dynamically
-        // SSL can be enabled/disabled in BoshEndpoint#setSslEnabled()
+    /**
+     * Updates the context with the session's {...@link HttpServletRequest} 
and {...@link HttpServletResponse}
+     * <p>
+     * The HTTP context is updated every time a new HTTP request is received.
+     * @param req
+     * @param resp
+     */
+    public void setHttpContext(HttpServletRequest req, HttpServletResponse 
resp) {
+        httpRequest = req;
+        httpRespone = resp;
+    }
+
+    /**
+     * Getter for the HTTP request
+     * @return
+     */
+    public HttpServletRequest getHttpRequest() {
+        return httpRequest;
+    }
+
+    /**
+     * Getter for the HTTP response
+     * @return
+     */
+    public HttpServletResponse getHttpResponse() {
+        return httpRespone;
+    }
+
+    /**
+     * Getter for the decoder
+     * @return
+     */
+    public BoshDecoder getDecoder() {
+        return boshDecoder;
     }
 }

Added: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java?rev=954138&view=auto
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
 (added)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshDecoder.java
 Sat Jun 12 20:53:38 2010
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.vysper.xmpp.extension.xep0124;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.mina.core.buffer.IoBuffer;
+import org.apache.vysper.charset.CharsetUtil;
+import org.apache.vysper.mina.codec.StanzaBuilderFactory;
+import org.apache.vysper.xml.decoder.XMPPContentHandler;
+import org.apache.vysper.xml.decoder.XMPPContentHandler.StanzaListener;
+import org.apache.vysper.xml.fragment.XMLElement;
+import org.apache.vysper.xml.sax.NonBlockingXMLReader;
+import org.apache.vysper.xml.sax.impl.DefaultNonBlockingXMLReader;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.xml.sax.SAXException;
+
+/**
+ * Decodes bytes into BOSH stanzas
+ * <p>
+ * Uses nbxml for XML processing.
+ * Every HTTP session has its own instance of BoshDecoder
+ * (because decoding state is associated with the decoder, and to ensure that
+ * the decoding errors of a session do not affect another session).
+ * 
+ * @author The Apache MINA Project ([email protected])
+ */
+public class BoshDecoder implements StanzaListener {
+
+    private final BoshHandler boshHandler;
+
+    private final NonBlockingXMLReader reader;
+
+    private final BoshBackedSessionContext sessionContext;
+
+    /**
+     * Creates a new decoder associated with a {...@link SessionContext}
+     * @param boshHandler
+     * @param sessionContext
+     */
+    public BoshDecoder(BoshHandler boshHandler,
+            BoshBackedSessionContext sessionContext) {
+        this.boshHandler = boshHandler;
+        this.sessionContext = sessionContext;
+        reader = new DefaultNonBlockingXMLReader();
+        XMPPContentHandler contentHandler = new XMPPContentHandler(
+                new StanzaBuilderFactory());
+        contentHandler.setListener(this);
+        reader.setContentHandler(contentHandler);
+    }
+
+    /**
+     * Decodes the bytes from the {...@link InputStream} provided by the 
current {...@link HttpServletRequest} of
+     * the session context into BOSH stanzas.
+     * @throws IOException
+     * @throws SAXException
+     */
+    public void decode() throws IOException, SAXException {
+        IoBuffer ioBuf = IoBuffer.allocate(1024);
+        ioBuf.setAutoExpand(true);
+        byte[] buf = new byte[1024];
+        InputStream in = sessionContext.getHttpRequest().getInputStream();
+
+        for (;;) {
+            int i = in.read(buf);
+            if (i == -1) {
+                break;
+            }
+            ioBuf.put(buf, 0, i);
+        }
+        ioBuf.flip();
+        reader.parse(ioBuf, CharsetUtil.UTF8_DECODER);
+    }
+
+    public void stanza(XMLElement element) {
+        boshHandler.processStanza(sessionContext, (Stanza) element);
+    }
+
+}
\ No newline at end of file

Added: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java?rev=954138&view=auto
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
 (added)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshHandler.java
 Sat Jun 12 20:53:38 2010
@@ -0,0 +1,59 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.vysper.xmpp.extension.xep0124;
+
+import java.io.IOException;
+import java.util.Random;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.vysper.xmpp.stanza.Stanza;
+
+/**
+ * Processes the BOSH requests from the clients and then responds back
+ * 
+ * @author The Apache MINA Project ([email protected])
+ */
+public class BoshHandler {
+
+    /**
+     * Handles the BOSH stanzas received from the decoder
+     * @param sessionContext
+     * @param stanza
+     */
+    public void processStanza(BoshBackedSessionContext sessionContext,
+            Stanza stanza) {
+        
+        // TODO
+        HttpServletResponse resp = sessionContext.getHttpResponse();
+        String sid = Long.toString(new Random().nextLong(), 16);
+        resp.setContentType("text/xml; charset=UTF-8");
+        try {
+            resp.getWriter().print("<body 
xmlns='http://jabber.org/protocol/httpbind' wait='60' inactivity='60' 
polling='5' requests='2' hold='1' maxpause='120' sid='");
+        resp.getWriter().print(sid);
+        resp.getWriter().print("' ver='1.6' from='vysper.org'/>");
+        resp.flushBuffer();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+}

Modified: 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
URL: 
http://svn.apache.org/viewvc/mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java?rev=954138&r1=954137&r2=954138&view=diff
==============================================================================
--- 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
 (original)
+++ 
mina/vysper/trunk/server/extensions/xep0124-xep0206-bosh/src/main/java/org/apache/vysper/xmpp/extension/xep0124/BoshServlet.java
 Sat Jun 12 20:53:38 2010
@@ -20,20 +20,20 @@
 package org.apache.vysper.xmpp.extension.xep0124;
 
 import java.io.BufferedInputStream;
-import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.util.Random;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
 
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
 
 /**
  * Handles BOSH requests from HTTP clients.
@@ -51,8 +51,12 @@ public class BoshServlet extends HttpSer
     private static final String XML_CONTENT_TYPE = "text/xml; charset=UTF-8";
 
     private static final String INFO_GET = "This is an XMPP BOSH connection 
manager, you need to use a compatible BOSH client to use its services!";
+    
+    private static final String SESSION_CONTEXT_ATTRIBUTE = 
"SESSION_CONTEXT_ATTRIBUTE";
 
     private final Logger logger = LoggerFactory.getLogger(BoshServlet.class);
+    
+    private final BoshHandler boshHandler = new BoshHandler();
 
     private ServerRuntimeContext serverRuntimeContext;
 
@@ -103,39 +107,26 @@ public class BoshServlet extends HttpSer
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
             throws ServletException, IOException {
-        BufferedReader reader = req.getReader();
-
-        char[] buf = new char[1024];
-        StringBuilder sb = new StringBuilder();
-
-        for (;;) {
-            int n = reader.read(buf);
-            if (n == -1) {
-                break;
-            }
-            sb.append(buf, 0, n);
+        HttpSession httpSession = req.getSession(true);
+        BoshBackedSessionContext sessionContext = (BoshBackedSessionContext) 
httpSession.getAttribute(SESSION_CONTEXT_ATTRIBUTE);
+        if (sessionContext == null) {
+            sessionContext = new 
BoshBackedSessionContext(serverRuntimeContext, boshHandler);
+            httpSession.setAttribute(SESSION_CONTEXT_ATTRIBUTE, 
sessionContext);
         }
-
-        String body = sb.toString();
-        logger.debug("BOSH CM received : {}", body);
-
-        // test if this is the first request (kind of a hack - should be 
parsing XML)
-        if (body.indexOf("sid=") == -1) {
-            // initial request
-            String sid = Long.toString(new Random().nextLong(), 16);
-            resp.setContentType(XML_CONTENT_TYPE);
-            resp.getWriter()
-                    .print("<body xmlns='http://jabber.org/protocol/httpbind' 
wait='60' inactivity='60' polling='5' requests='2' hold='1' maxpause='120' 
sid='");
-            resp.getWriter().print(sid);
-            resp.getWriter().print("' ver='1.6' from='vysper.org'/>");
-            resp.flushBuffer();
-            return;
+        
+        /*
+         * The following block is synchronized on the session context to 
prevent simultaneous
+         * access from a session (simultaneous access is possible in certain 
cases because of the 
+         * nature of HTTP sessions tracking mechanism - cookies, URL rewrites, 
etc).
+         */
+        synchronized (sessionContext) {
+            sessionContext.setHttpContext(req, resp);
+            try {
+                sessionContext.getDecoder().decode();
+            } catch (SAXException e) {
+                logger.error("Exception thrown while decoding XML", e);
+            }            
         }
-
-        // session exists
-        // not handled yet, TODO
-        resp.setContentType(XML_CONTENT_TYPE);
-        resp.flushBuffer();
     }
 
 }


Reply via email to