You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by be...@apache.org on 2010/03/10 19:18:21 UTC

svn commit: r921497 - in /mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp: modules/core/im/handler/ protocol/commandstanza/ server/ stanza/ state/resourcebinding/

Author: berndf
Date: Wed Mar 10 18:18:20 2010
New Revision: 921497

URL: http://svn.apache.org/viewvc?rev=921497&view=rev
Log:
VYSPER-185: communicate end-of-session-cause to the handler, shield against duplicate handling and races, do not send unavailable to self after stream error

Added:
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/CommandStanza.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/EndOfSessionCommandStanza.java
Modified:
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/AbstractSessionContext.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/SessionContext.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/PresenceStanza.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/StanzaBuilder.java
    mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java Wed Mar 10 18:18:20 2010
@@ -34,6 +34,7 @@ import org.apache.vysper.xmpp.modules.ro
 import org.apache.vysper.xmpp.modules.roster.RosterUtils;
 import org.apache.vysper.xmpp.modules.roster.SubscriptionType;
 import org.apache.vysper.xmpp.modules.roster.persistence.RosterManager;
+import org.apache.vysper.xmpp.protocol.commandstanza.EndOfSessionCommandStanza;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionContext;
 import org.apache.vysper.xmpp.server.response.ServerErrorResponses;
@@ -91,7 +92,7 @@ public class PresenceAvailabilityHandler
         XMPPCoreStanzaVerifier verifier = presenceStanza.getCoreVerifier();
         ResourceRegistry registry = serverRuntimeContext.getResourceRegistry();
 
-        // check if presence reception is turned of either globally or locally
+        // check if presence reception is turned off either globally or locally
         if (!serverRuntimeContext.getServerFeatures().isRelayingPresence() ||
             (sessionContext != null && 
              sessionContext.getAttribute(SessionContext.SESSION_ATTRIBUTE_PRESENCE_STANZA_NO_RECEIVE) != null)) {
@@ -150,10 +151,18 @@ public class PresenceAvailabilityHandler
                 rosterManager, user, registry, true);
 
         if (!user.isResourceSet()) throw new RuntimeException("resource id not available");
-        registry.setResourceState(user.getResource(), ResourceState.UNAVAILABLE);
+        boolean stateChanged = registry.setResourceState(user.getResource(), ResourceState.UNAVAILABLE);
+        // avoid races from closing connections and unavail presence stanza handlings happening quasi-concurrently
+        if (!stateChanged) return null;
 
         sessionContext.getServerRuntimeContext().getPresenceCache().remove(user);
 
+        SessionContext.SessionTerminationCause terminationCause = null;
+        if (presenceStanza instanceof EndOfSessionCommandStanza) {
+            EndOfSessionCommandStanza commandStanza = (EndOfSessionCommandStanza) presenceStanza;
+            terminationCause = commandStanza.getSessionTerminationCause();
+        }
+
         // TODO check if we do have to do something about resource priority
 
         List<Entity> contacts = new ArrayList<Entity>();
@@ -185,6 +194,9 @@ public class PresenceAvailabilityHandler
         // broadcast presence notification to all resources of
         // current entity.
         List<String> resources = registry.getAvailableResources(user);
+        if (!SessionContext.SessionTerminationCause.isClientReceivingStanzas(terminationCause)) {
+            resources.remove(user.getResource());
+        }
         for (String resource : resources) {
             Entity otherResource = new EntityImpl(user, resource);
             contacts.add(otherResource);

Added: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/CommandStanza.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/CommandStanza.java?rev=921497&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/CommandStanza.java (added)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/CommandStanza.java Wed Mar 10 18:18:20 2010
@@ -0,0 +1,26 @@
+/*
+ *  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.protocol.commandstanza;
+
+/**
+ * marker/mix-in interface for stanza which carry special command semantics 
+ */
+public interface CommandStanza {
+}

Added: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/EndOfSessionCommandStanza.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/EndOfSessionCommandStanza.java?rev=921497&view=auto
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/EndOfSessionCommandStanza.java (added)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/protocol/commandstanza/EndOfSessionCommandStanza.java Wed Mar 10 18:18:20 2010
@@ -0,0 +1,41 @@
+/*
+ *  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.protocol.commandstanza;
+
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.stanza.PresenceStanza;
+import org.apache.vysper.xmpp.stanza.Stanza;
+
+/**
+ * presence command stanza used for presence-unavailable to carry the reason in case the session is in termination
+ */
+public class EndOfSessionCommandStanza extends PresenceStanza implements CommandStanza {
+
+    protected SessionContext.SessionTerminationCause sessionTerminationCause;
+
+    public EndOfSessionCommandStanza(Stanza stanza, SessionContext.SessionTerminationCause sessionTerminationCause) {
+        super(stanza);
+        this.sessionTerminationCause = sessionTerminationCause;
+    }
+
+    public SessionContext.SessionTerminationCause getSessionTerminationCause() {
+        return sessionTerminationCause;
+    }
+}

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/AbstractSessionContext.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/AbstractSessionContext.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/AbstractSessionContext.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/AbstractSessionContext.java Wed Mar 10 18:18:20 2010
@@ -21,22 +21,30 @@
 package org.apache.vysper.xmpp.server;
 
 import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.protocol.ProtocolException;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
+import org.apache.vysper.xmpp.protocol.StanzaHandler;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 import org.apache.vysper.xmpp.state.resourcebinding.BindException;
 import org.apache.vysper.xmpp.uuid.JVMBuiltinUUIDGenerator;
 import org.apache.vysper.xmpp.uuid.UUIDGenerator;
 import org.apache.vysper.xmpp.writer.StanzaWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.HashMap;
 import java.util.Map;
 
 /**
  * provides default session context behavior
- *
+ * 
  * @author The Apache MINA Project (dev@mina.apache.org)
  */
 public abstract class AbstractSessionContext implements SessionContext {
 
+    private static final Logger logger = LoggerFactory.getLogger(AbstractSessionContext.class);
+    
     protected ServerRuntimeContext serverRuntimeContext;
     protected String sessionId;
     protected String xmlLang;
@@ -108,14 +116,32 @@ public abstract class AbstractSessionCon
     }
 
     public void endSession(SessionTerminationCause terminationCause) {
-        StanzaWriter stanzaWriter = getResponseWriter();
-        stanzaWriter.close();
-        sessionStateHolder.setState(SessionState.CLOSED); // no more traffic going through
-        getServerRuntimeContext().getResourceRegistry().unbindSession(this);
-        // TODO send unavailable to all contacts and other resources
-        // TODO remove latest availability from LatestPresenceCache
-        // TODO close underlying transport (TCP socket)
-    }
+		StanzaWriter stanzaWriter = getResponseWriter();
+		stanzaWriter.close();
+
+        if (terminationCause == null) {
+            throw new RuntimeException("no termination cause given");
+        }
+
+		if (terminationCause == SessionTerminationCause.CLIENT_BYEBYE ||
+            terminationCause == SessionTerminationCause.CONNECTION_ABORT ||
+            terminationCause == SessionTerminationCause.STREAM_ERROR) {
+            Stanza unavailableStanza = StanzaBuilder.createUnavailablePresenceStanza(null, terminationCause);
+            StanzaHandler handler = serverRuntimeContext.getHandler(unavailableStanza);
+            try {
+                handler.execute(unavailableStanza, serverRuntimeContext, true, this, sessionStateHolder);
+            } catch (ProtocolException e) {
+                logger.error("Failed to send unavailable stanza on connection close", e);
+            }
+        } else if (terminationCause == SessionTerminationCause.SERVER_SHUTDOWN) {
+            // do nothing
+        } else {
+            throw new IllegalArgumentException("endSession() not implemented for termination cause");
+        }
+
+        sessionStateHolder.setState(SessionState.CLOSED); // no more traffic
+		// TODO close underlying transport (TCP socket)
+	}
 
     public Entity getServerJID() {
         return serverEntity;

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/SessionContext.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/SessionContext.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/SessionContext.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/server/SessionContext.java Wed Mar 10 18:18:20 2010
@@ -51,9 +51,14 @@ public interface SessionContext {
          * the server signalled a stream error to the client and subsequently needs
          * to close the session down 
          */
-        STREAM_ERROR, 
+        STREAM_ERROR;
+
+        public static boolean isClientReceivingStanzas(SessionTerminationCause cause) {
+            return cause == null || cause == SERVER_SHUTDOWN || cause == CLIENT_BYEBYE; 
+        }
+
     }
-    
+
 	/**
 	 * Gets the {@link ServerRuntimeContext}.
 	 *

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/PresenceStanza.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/PresenceStanza.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/PresenceStanza.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/PresenceStanza.java Wed Mar 10 18:18:20 2010
@@ -93,10 +93,10 @@ public class PresenceStanza extends XMPP
             try {
                 intValue = Integer.parseInt(priorityString);
             } catch (NumberFormatException e) {
-                throw new XMLSemanticError("presence priority must be an imteger value in the -128 to 127 range", e);
+                throw new XMLSemanticError("presence priority must be an integer value in the -128 to 127 range", e);
             }
             if (intValue < -128 || intValue > 127) {
-                throw new XMLSemanticError("presence priority must be an imteger value in the -128 to 127 range");
+                throw new XMLSemanticError("presence priority must be an integer value in the -128 to 127 range");
             }
             priorityValue = intValue;
         }

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/StanzaBuilder.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/StanzaBuilder.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/StanzaBuilder.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/StanzaBuilder.java Wed Mar 10 18:18:20 2010
@@ -31,6 +31,8 @@ import org.apache.vysper.xml.fragment.XM
 import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.addressing.EntityImpl;
 import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.protocol.commandstanza.EndOfSessionCommandStanza;
+import org.apache.vysper.xmpp.server.SessionContext;
 
 /**
  *
@@ -62,6 +64,16 @@ public class StanzaBuilder extends Abstr
         return stanzaBuilder;
     }
 
+    public static Stanza createUnavailablePresenceStanza(String status, SessionContext.SessionTerminationCause terminationCause) {
+        StanzaBuilder presenceUnavailBuilder = createPresenceStanza(null, null, null, PresenceStanzaType.UNAVAILABLE, null, status);
+        if (terminationCause == null) {
+            return presenceUnavailBuilder.build();
+        }
+        else {
+            return new EndOfSessionCommandStanza(presenceUnavailBuilder.build(), terminationCause);
+        }
+    }
+
     public static StanzaBuilder createPresenceStanza(Entity from, Entity to, String lang, PresenceStanzaType type, String show, String status) {
         StanzaBuilder stanzaBuilder = new StanzaBuilder("presence", NamespaceURIs.JABBER_CLIENT);
         if (from != null) stanzaBuilder.addAttribute("from", from.getFullQualifiedName());

Modified: mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java
URL: http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java?rev=921497&r1=921496&r2=921497&view=diff
==============================================================================
--- mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java (original)
+++ mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java Wed Mar 10 18:18:20 2010
@@ -324,13 +324,18 @@ public class ResourceRegistry {
 	 *            the resource identifier
 	 * @param state
 	 *            the {@link ResourceState} to set
+     * @return true iff the state has effectively changed
 	 */
-	public void setResourceState(String resourceId, ResourceState state) {
+	public boolean setResourceState(String resourceId, ResourceState state) {
 		SessionData data = boundResources.get(resourceId);
-		if (data == null) {
+        if (data == null) {
             throw new IllegalArgumentException("resource not registered: " + resourceId);
         }
-        data.state = state;
+        synchronized (data) {
+            boolean result =  data.state != state;
+            data.state = state;
+            return result;
+        }
 	}
 
     /**