I'm sorry to say that, but commit this breaks

MUCIntegrationTestCase.testSendMessageToRoom

where a stanza gets send
from: [email protected]/Nick
to: [email protected]

However, the server now refuses to relay that to the client, because it
is a GROUPCHAT message sent to a BARE JID.
This triggers 3921-bis 8.3.1.1:

>>>
For a message of type "groupchat" [sent to a bare JID], the server MUST
NOT deliver the stanza to any of the available resources but instead
MUST return a stanza error to the sender, which SHOULD be
<service-unavailable/>.
<<<<

I'd expect this to be relayed to the FULL JID (incl. resource id) of the
user, which would go through fine.

The MUC spec says that private messages must not be GROUPCHAT, but CHAT.
Additionally, the MUC spec delivers any message to the FULL JID of the
client.

Is this a problem with Smack or with the test setup or anything else?

Anyone a clue?

  Bernd

[email protected] wrote:
> 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