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;
+ }
}
/**