Author: berndf
Date: Mon Aug 24 12:31:59 2009
New Revision: 807187

URL: http://svn.apache.org/viewvc?rev=807187&view=rev
Log:
VYSPER-179: change stanza delivery to the highest priorized receiver, instead 
of delivering to all possible receivers
VYSPER-181: cover more delivery rules on inbound relay

Added:
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveredToOfflineReceiverException.java
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/OfflineStanzaReceiver.java
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/ServiceNotAvailableException.java
Modified:
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveringInboundStanzaRelay.java
    
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/stanza/MessageStanza.java
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanzaType.java
    
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistry.java
    
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistryTestCase.java

Added: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveredToOfflineReceiverException.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveredToOfflineReceiverException.java?rev=807187&view=auto
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveredToOfflineReceiverException.java
 (added)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveredToOfflineReceiverException.java
 Mon Aug 24 12:31:59 2009
@@ -0,0 +1,22 @@
+package org.apache.vysper.xmpp.delivery;
+
+/**
+ * this class is thrown if message has not been delivered and was haned over 
for offline storage
+ */
+public class DeliveredToOfflineReceiverException extends DeliveryException {
+    public DeliveredToOfflineReceiverException() {
+        super();
+    }
+
+    public DeliveredToOfflineReceiverException(String string) {
+        super(string);
+    }
+
+    public DeliveredToOfflineReceiverException(String string, Throwable 
throwable) {
+        super(string, throwable);
+    }
+
+    public DeliveredToOfflineReceiverException(Throwable throwable) {
+        super(throwable);
+    }
+}

Modified: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveringInboundStanzaRelay.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveringInboundStanzaRelay.java?rev=807187&r1=807186&r2=807187&view=diff
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveringInboundStanzaRelay.java
 (original)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/DeliveringInboundStanzaRelay.java
 Mon Aug 24 12:31:59 2009
@@ -19,6 +19,7 @@
  */
 package org.apache.vysper.xmpp.delivery;
 
+import org.apache.vysper.storage.StorageProviderRegistry;
 import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.authorization.AccountManagement;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
@@ -27,24 +28,31 @@
 import org.apache.vysper.xmpp.server.SessionContext;
 import org.apache.vysper.xmpp.server.SessionState;
 import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.XMPPCoreStanza;
+import org.apache.vysper.xmpp.stanza.IQStanza;
+import org.apache.vysper.xmpp.stanza.PresenceStanza;
+import org.apache.vysper.xmpp.stanza.MessageStanza;
+import org.apache.vysper.xmpp.stanza.MessageStanzaType;
 import org.apache.vysper.xmpp.state.resourcebinding.ResourceRegistry;
-import org.apache.vysper.storage.StorageProviderRegistry;
+import org.apache.vysper.compliance.SpecCompliant;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.List;
+import java.util.ArrayList;
 
 /**
- * relays stanzas to internal sessions, acts as a 'stage' by using a 
ThreadPoolExecutor
- * TODO: re-work the whole relay result
- *
+ * relays all 'incoming' stanzas to internal sessions, acts as a 'stage' by 
using a ThreadPoolExecutor
+ * 'incoming' here means:
+ * a. stanzas coming in from other servers
+ * b. stanzas coming from other (local) sessions and are targeted to clients 
on this server
+ *  
  * @author The Apache MINA Project ([email protected])
  */
 public class DeliveringInboundStanzaRelay implements StanzaRelay {
@@ -53,9 +61,12 @@
 
     private static final InboundStanzaProtocolWorker 
INBOUND_STANZA_PROTOCOL_WORKER = new InboundStanzaProtocolWorker();
 
+    private static final Integer PRIO_THRESHOLD = 0;
+    
     protected ResourceRegistry resourceRegistry;
     protected ExecutorService executor;
     protected AccountManagement accountVerification;
+    protected OfflineStanzaReceiver offlineStanzaReceiver = null;
 
     public DeliveringInboundStanzaRelay(ResourceRegistry resourceRegistry, 
StorageProviderRegistry storageProviderRegistry) {
         this(resourceRegistry, 
(AccountManagement)storageProviderRegistry.retrieve(AccountManagement.class));
@@ -118,49 +129,151 @@
             return relayResult;
         }
 
+        /**
+         * @return
+         */
+        @SpecCompliant(spec="draft-ietf-xmpp-3921bis-00", section="8.", 
status= SpecCompliant.ComplianceStatus.IN_PROGRESS, coverage = 
SpecCompliant.ComplianceCoverage.COMPLETE)
         protected RelayResult deliver() {
-            List<RelayResult> relayResults = new ArrayList<RelayResult>();
             try {
-                if (!accountVerification.verifyAccountExists(receiver)) {
-                    logger.warn("cannot relay to unexisting receiver {} stanza 
{}", receiver.getFullQualifiedName(), stanza.toString());
-                    return new RelayResult(new NoSuchLocalUserException());
-                }
-                List<SessionContext> receivingSessions = 
resourceRegistry.getSessions(receiver);
-                if (receivingSessions == null || receivingSessions.size() == 
0) {
-                    logger.warn("cannot relay to offline receiver {} stanza 
{}", receiver.getFullQualifiedName(), stanza.toString());
-                    return new RelayResult(new 
LocalRecipientOfflineException());
+                if (receiver.isResourceSet()) {
+                    return deliverToFullJID();
                 } else {
-                    relayToSessions(relayResults, receivingSessions);
+                    return deliverToBareJID();
                 }
+
             } catch (RuntimeException e) {
                 return new RelayResult(new DeliveryException(e));
             }
+        }
 
-            // TODO handle this properly, don't only return the first failure
-            for (RelayResult relayResult : relayResults) {
-                if (!relayResult.isRelayed()) return relayResult;
+        @SpecCompliant(spec="draft-ietf-xmpp-3921bis-00", section="8.3.", 
status= SpecCompliant.ComplianceStatus.IN_PROGRESS, coverage = 
SpecCompliant.ComplianceCoverage.COMPLETE)
+        private RelayResult deliverToBareJID() {
+            XMPPCoreStanza xmppStanza = XMPPCoreStanza.getWrapper(stanza);
+            if (xmppStanza == null) new RelayResult(new 
DeliveryException("unable to deliver stanza which is not IQ, presence or 
message"));
+
+            if (PresenceStanza.isOfType(stanza)) {
+                return relayToAllSessions();
+            } else if (MessageStanza.isOfType(stanza)) {
+                MessageStanza messageStanza = (MessageStanza)xmppStanza;
+                MessageStanzaType messageStanzaType = 
messageStanza.getMessageType();
+                switch (messageStanzaType) {
+                    case CHAT:
+                    case NORMAL:
+                        return relayToBestSession(false);
+                    
+                    case ERROR:
+                        // silently ignore
+                        return null;
+                    
+                    case GROUPCHAT:
+                        return new RelayResult(new 
ServiceNotAvailableException());
+                        
+                    case HEADLINE:
+                        return relayToAllSessions();
+                    
+                    default:
+                        throw new RuntimeException("unhandled message type " + 
messageStanzaType.value());
+                }
+            } else if (IQStanza.isOfType(stanza)) {
+                // TODO handle on behalf of the user/client
+                throw new RuntimeException("inbound IQ not yet handled");
             }
-            return new RelayResult(); // return success result
+
+            return relayNotPossible();
         }
 
-        protected void relayToSessions(List<RelayResult> relayResults, 
List<SessionContext> receivingSessions) {
-            if (receivingSessions.size() > 1) {
-                logger.warn("multiplexing: {} sessions will be processing {} 
", receivingSessions.size(), stanza);
+        @SpecCompliant(spec="draft-ietf-xmpp-3921bis-00", section="8.2.", 
status= SpecCompliant.ComplianceStatus.IN_PROGRESS, coverage = 
SpecCompliant.ComplianceCoverage.COMPLETE)
+        private RelayResult deliverToFullJID() {
+            XMPPCoreStanza xmppStanza = XMPPCoreStanza.getWrapper(stanza);
+            if (xmppStanza == null) new RelayResult(new 
DeliveryException("unable to deliver stanza which is not IQ, presence or 
message"));
+
+            // all special cases are handled by the inbound handlers!
+            if (PresenceStanza.isOfType(stanza)) {
+                // TODO cannot deliver presence with type  AVAIL or UNAVAIL: 
silently ignore
+                // TODO cannot deliver presence with type  SUBSCRIBE: see 
3921bis section 3.1.3
+                // TODO cannot deliver presence with type  (UN)SUBSCRIBED, 
UNSUBSCRIBE: silently ignore
+                return relayToBestSession(false);
+            } else if (MessageStanza.isOfType(stanza)) {
+                MessageStanza messageStanza = (MessageStanza)xmppStanza;
+                MessageStanzaType messageStanzaType = 
messageStanza.getMessageType();
+                boolean fallbackToBareJIDAllowed = messageStanzaType == 
MessageStanzaType.CHAT || 
+                                                   messageStanzaType == 
MessageStanzaType.HEADLINE ||
+                                                   messageStanzaType == 
MessageStanzaType.NORMAL;
+                // TODO cannot deliver ERROR: silently ignore
+                // TODO cannot deliver GROUPCHAT: service n/a
+                return relayToBestSession(fallbackToBareJIDAllowed);
+
+            } else if (IQStanza.isOfType(stanza)) {
+                // TODO no resource matches: service n/a
+                return relayToBestSession(false);
             }
-            for (SessionContext sessionContext : receivingSessions) {
-                if (sessionContext.getState() != SessionState.AUTHENTICATED) {
-                    relayResults.add(new RelayResult(new DeliveryException("no 
relay to non-authenticated sessions")));
-                    continue;
-                }
-                try {
-                    StanzaHandler stanzaHandler = 
sessionContext.getServerRuntimeContext().getHandler(stanza);
-                    
INBOUND_STANZA_PROTOCOL_WORKER.processStanza(sessionContext, 
sessionStateHolder, stanza, stanzaHandler);
-                } catch (Exception e) {
-                    // TODO do not break out here. we should try to deliver to 
the others first!
-                    relayResults.add(new RelayResult(new 
DeliveryException(e)));
-                }
+ 
+            // for any other type of stanza 
+            return new RelayResult(new ServiceNotAvailableException());
+        }
+
+        private RelayResult relayNotPossible() {
+            if (!accountVerification.verifyAccountExists(receiver)) {
+                logger.warn("cannot relay to unexisting receiver {} stanza 
{}", receiver.getFullQualifiedName(), stanza.toString());
+                return new RelayResult(new NoSuchLocalUserException());
+            } else if (offlineStanzaReceiver != null) {
+                offlineStanzaReceiver.receive(stanza);
+                return new RelayResult(new 
DeliveredToOfflineReceiverException());
+            } else {
+                logger.warn("cannot relay to offline receiver {} stanza {}", 
receiver.getFullQualifiedName(), stanza.toString());
+                return new RelayResult(new LocalRecipientOfflineException());
             }
         }
+
+        protected RelayResult relayToBestSession(final boolean 
fallbackToBareJIDAllowed) {
+            SessionContext receivingSession = 
resourceRegistry.getHighestPrioSession(receiver, PRIO_THRESHOLD);
+
+            if (receivingSession == null && receiver.isResourceSet() && 
fallbackToBareJIDAllowed) {
+                // no concrete session for this resource has been found
+                // fall back to bare JID
+                receivingSession = 
resourceRegistry.getHighestPrioSession(receiver.getBareJID(), PRIO_THRESHOLD);
+            }
+
+            if (receivingSession == null) {
+                return relayNotPossible();
+            }
+            
+            if (receivingSession.getState() != SessionState.AUTHENTICATED) {
+                return new RelayResult(new DeliveryException("no relay to 
non-authenticated sessions"));
+            }
+            try {
+                StanzaHandler stanzaHandler = 
receivingSession.getServerRuntimeContext().getHandler(stanza);
+                INBOUND_STANZA_PROTOCOL_WORKER.processStanza(receivingSession, 
sessionStateHolder, stanza, stanzaHandler);
+            } catch (Exception e) {
+                return new RelayResult(new DeliveryException(e));
+            }
+            return new RelayResult(); // return success result
+        }
+        
+        protected RelayResult relayToAllSessions() {
+            // the individual results are currently only recorded pro forma
+            List<RelayResult> relayResults = new ArrayList<RelayResult>();
+            
+            List<SessionContext> receivingSessions = 
resourceRegistry.getSessions(receiver);
+
+            if (receivingSessions.size() > 1) {
+                 logger.warn("multiplexing: {} sessions will be processing {} 
", receivingSessions.size(), stanza);
+             }
+             for (SessionContext sessionContext : receivingSessions) {
+                 if (sessionContext.getState() != SessionState.AUTHENTICATED) {
+                     relayResults.add(new RelayResult(new 
DeliveryException("no relay to non-authenticated sessions")));
+                     continue;
+                 }
+                 try {
+                     StanzaHandler stanzaHandler = 
sessionContext.getServerRuntimeContext().getHandler(stanza);
+                     
INBOUND_STANZA_PROTOCOL_WORKER.processStanza(sessionContext, 
sessionStateHolder, stanza, stanzaHandler);
+                 } catch (Exception e) {
+                     relayResults.add(new RelayResult(new 
DeliveryException(e)));
+                 }
+             }
+                
+             return new RelayResult(); // return success result
+         }
     }
 
     private static class UnmodifyableSessionStateHolder extends 
SessionStateHolder {

Added: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/OfflineStanzaReceiver.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/OfflineStanzaReceiver.java?rev=807187&view=auto
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/OfflineStanzaReceiver.java
 (added)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/OfflineStanzaReceiver.java
 Mon Aug 24 12:31:59 2009
@@ -0,0 +1,13 @@
+package org.apache.vysper.xmpp.delivery;
+
+import org.apache.vysper.xmpp.stanza.Stanza;
+
+/**
+ * receives stanzas addressed to offline receivers
+ * TODO: this is more or less a placeholder interface currently.
+ */
+public interface OfflineStanzaReceiver {
+
+    public void receive(Stanza stanza);
+    
+}

Added: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/ServiceNotAvailableException.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/ServiceNotAvailableException.java?rev=807187&view=auto
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/ServiceNotAvailableException.java
 (added)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/delivery/ServiceNotAvailableException.java
 Mon Aug 24 12:31:59 2009
@@ -0,0 +1,21 @@
+package org.apache.vysper.xmpp.delivery;
+
+/**
+ */
+public class ServiceNotAvailableException extends DeliveryException {
+    public ServiceNotAvailableException() {
+        super();
+    }
+
+    public ServiceNotAvailableException(String string) {
+        super(string);
+    }
+
+    public ServiceNotAvailableException(String string, Throwable throwable) {
+        super(string, throwable);
+    }
+
+    public ServiceNotAvailableException(Throwable throwable) {
+        super(throwable);
+    }
+}

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=807187&r1=807186&r2=807187&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
 Mon Aug 24 12:31:59 2009
@@ -200,7 +200,8 @@
                 rosterManager, user, registry);
 
         if (!user.isResourceSet()) throw new RuntimeException("resource id not 
available");
-        ResourceState resourceState = 
registry.getResourceState(user.getResource());
+        String resourceId = user.getResource();
+        ResourceState resourceState = registry.getResourceState(resourceId);
 
         boolean isPresenceUpdate = resourceState != null && 
ResourceState.isAvailable(resourceState);
 
@@ -213,11 +214,14 @@
             // things to be done for initial presence
 
             // set resource state
-            ResourceState currentState = 
registry.getResourceState(user.getResource());
+            ResourceState currentState = registry.getResourceState(resourceId);
             // set to AVAILABLE, but do not override AVAILABLE_INTERESTED
-            registry.setResourceState(user.getResource(), 
ResourceState.makeAvailable(currentState));
+            registry.setResourceState(resourceId, 
ResourceState.makeAvailable(currentState));
         }
-        updateResourcePriority(registry, sessionContext.getInitiatingEntity(), 
presenceStanza.getPrioritySafe());
+        
+        // the presence priority is optional, but if contained, it might 
become relevant for
+        // message delivery (see RFC3921bis-05#8.3.1.1)
+        registry.setResourcePriority(resourceId, 
presenceStanza.getPrioritySafe());
 
         List<Entity> contacts = new ArrayList<Entity>();
 
@@ -365,15 +369,6 @@
         return stanza;
        }
 
-    /**
-     * the presence priority is optional, but if contained, it might become 
relevant for
-     * message delivery (see RFC3921bis-05#8.3.1.1)
-     */
-    private void updateResourcePriority(ResourceRegistry registry, Entity 
initiatingEntity, int priority) {
-        if (initiatingEntity == null || initiatingEntity.getResource() == 
null) return;
-        registry.setResourcePriority(initiatingEntity.getResource(), priority);
-    }
-
     private void relayTo(Entity from, List<Entity> tos, PresenceStanza 
original, SessionContext sessionContext) {
         List<Attribute> toFromReplacements = new ArrayList<Attribute>();
         toFromReplacements.add(new Attribute("from", 
from.getFullQualifiedName()));

Modified: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanza.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanza.java?rev=807187&r1=807186&r2=807187&view=diff
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanza.java
 (original)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanza.java
 Mon Aug 24 12:31:59 2009
@@ -54,7 +54,6 @@
 
     public MessageStanzaType getMessageType() {
         String type = getType();
-        if (type == null) return null;
         return MessageStanzaType.valueOfWithDefault(type);
     }
 

Modified: 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanzaType.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanzaType.java?rev=807187&r1=807186&r2=807187&view=diff
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanzaType.java
 (original)
+++ 
mina/sandbox/vysper/trunk/server/core/src/main/java/org/apache/vysper/xmpp/stanza/MessageStanzaType.java
 Mon Aug 24 12:31:59 2009
@@ -39,6 +39,7 @@
      * given
      */
     public static MessageStanzaType valueOfWithDefault(String value) {
+        if (value == null) return NORMAL;
         try {
             return MessageStanzaType.valueOf(value.toUpperCase());
         } catch (IllegalArgumentException e) {

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=807187&r1=807186&r2=807187&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
 Mon Aug 24 12:31:59 2009
@@ -109,7 +109,8 @@
                                 resourceForEntityList);
                     }
                     resourceForEntityList.add(resourceId);
-                    logger.info("added resource no. " + 
resourceForEntityList.size() + " to entity {} <- {}", 
initiatingEntity.getFullQualifiedName(), resourceId);
+                    logger.info("added resource no. " + 
resourceForEntityList.size() + " to entity {} <- {}", 
+                                initiatingEntity.getFullQualifiedName(), 
resourceId);
 
                     List<String> resourcesForSessionList = 
sessionResources.get(sessionContext);
                     if (resourcesForSessionList == null) {
@@ -117,7 +118,8 @@
                         sessionResources.put(sessionContext, 
resourcesForSessionList);
                     }
                     resourcesForSessionList.add(resourceId);
-                    logger.info("added resource no. " + 
resourcesForSessionList.size() + " to session {} <- {}", 
sessionContext.getSessionId(), resourceId);
+                    logger.info("added resource no. " + 
resourcesForSessionList.size() + " to session {} <- {}", 
+                                sessionContext.getSessionId(), resourceId);
                 }
                        }
                }
@@ -276,6 +278,45 @@
                return sessionContexts;
        }
 
+    
+    /**
+     * retrieves the highest priorizes session for this entity. 
+     * 
+     * @param entity if this is not a bare JID, only the session for the JID's 
resource part will be returned, without
+     * looking at other sessions for the resource's bare JID. otherwise, in 
case of a full JID, it will return the 
+     * highest priorized session.
+     * @param prioThreshold if not NULL, only resources will be returned 
having same or higher priority. a common value 
+     * for the threshold is 0 (zero). 
+     * @return for a bare JID, it will return the hightest priorized session. 
for a full JID, it will return the 
+     * related session.
+     */
+    public SessionContext getHighestPrioSession(Entity entity, Integer 
prioThreshold) {
+        Integer currentPrio = Integer.MIN_VALUE;
+        SessionData result = null;
+
+        boolean isResourceSet = entity.isResourceSet();
+
+        List<String> boundResourceIds = getBoundResources(entity, false);
+               for (String resourceId : boundResourceIds) {
+            SessionData sessionData = boundResources.get(resourceId);
+            if (sessionData == null) continue;
+            
+            if (isResourceSet) return sessionData.context; // no prio checks, 
take the first proper one
+            
+            if (sessionData.priority > currentPrio) {
+                currentPrio = sessionData.priority;
+                result = sessionData;
+            }
+        }
+
+        if (prioThreshold != null && prioThreshold > currentPrio) {
+            // no session over threshold 
+            return null;
+        }
+
+               return result == null ? null : result.context;
+       }
+
     /**
         * Sets the {...@link ResourceState} for the given resource.
         *

Modified: 
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistryTestCase.java
URL: 
http://svn.apache.org/viewvc/mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistryTestCase.java?rev=807187&r1=807186&r2=807187&view=diff
==============================================================================
--- 
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistryTestCase.java
 (original)
+++ 
mina/sandbox/vysper/trunk/server/core/src/test/java/org/apache/vysper/xmpp/state/resourcebinding/ResourceRegistryTestCase.java
 Mon Aug 24 12:31:59 2009
@@ -75,9 +75,11 @@
         
         TestSessionContext sessionContext1 = 
TestSessionContext.createSessionContext(entity);
         String resourceId1 = resourceRegistry.bindSession(sessionContext1);
+        resourceRegistry.setResourcePriority(resourceId1, -1);
         
         TestSessionContext sessionContext2 = 
TestSessionContext.createSessionContext(entity);
         String resourceId2 = resourceRegistry.bindSession(sessionContext2);
+        resourceRegistry.setResourcePriority(resourceId2, 1);
         
         assertNotNull(resourceId1);
         assertNotNull(resourceId2);
@@ -91,6 +93,20 @@
         assertEquals(2, resourceList.size());
         assertTrue(sessionList.contains(sessionContext1));
         assertTrue(sessionList.contains(sessionContext2));
+        
+        SessionContext hightestPrioSession = 
resourceRegistry.getHighestPrioSession(entity, null);
+        assertSame(resourceRegistry.getSessionContext(resourceId2), 
hightestPrioSession);
+        
+        resourceRegistry.setResourcePriority(resourceId1, 2); // make this 
highes prio
+        hightestPrioSession = resourceRegistry.getHighestPrioSession(entity, 
null);
+        assertSame(resourceRegistry.getSessionContext(resourceId1), 
hightestPrioSession);
+
+        hightestPrioSession = resourceRegistry.getHighestPrioSession(entity, 
2); // still highest prio
+        assertSame(resourceRegistry.getSessionContext(resourceId1), 
hightestPrioSession);
+        
+        hightestPrioSession = resourceRegistry.getHighestPrioSession(entity, 
3); // now, all prios are below threshold
+        assertNull(hightestPrioSession);
+        
     }
 
     public void testAddOneEntityMultipleResources_TolerateResourceIds() throws 
EntityFormatException {


Reply via email to