/* * 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; import org.apache.vysper.xml.fragment.XMLElement; import org.apache.vysper.xmpp.addressing.Entity; import org.apache.vysper.xmpp.modules.core.base.handler.IQHandler; import org.apache.vysper.xmpp.modules.core.base.handler.MessageHandler; import org.apache.vysper.xmpp.modules.core.base.handler.RelayingIQHandler; import org.apache.vysper.xmpp.modules.core.base.handler.StreamStartHandler; import org.apache.vysper.xmpp.modules.core.base.handler.XMLPrologHandler; import org.apache.vysper.xmpp.modules.core.im.handler.PresenceHandler; import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbResultHandler; import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbVerifyHandler; import org.apache.vysper.xmpp.server.ServerRuntimeContext; import org.apache.vysper.xmpp.stanza.Stanza; import org.apache.vysper.xmpp.stanza.XMPPCoreStanza; /** * for effeciently looking up the right handler for a stanza. at first this class tries to determine the stanza's * specific namespace which uniquely brings up a NamespaceHandlerDictionary. then, all handlers in this directory * are visited and can verify if they might want to handle the stanza. the first affirmative handler lucks out and * can handle the stanza. regardless what comes out of this handler, no other handler will then be tasked with * handling. * * @author The Apache MINA Project (dev@mina.apache.org) */ public class StanzaHandlerLookup extends AbstractStanzaHandlerLookup { private IQHandler iqHandler = new RelayingIQHandler(); private MessageHandler messageHandler = new MessageHandler(); private PresenceHandler presenceHandler = new PresenceHandler(); private static final ServiceUnavailableStanzaErrorHandler SERVICE_UNAVAILABLE_STANZA_ERROR_HANDLER = new ServiceUnavailableStanzaErrorHandler(); protected ServerRuntimeContext serverRuntimeContext; public StanzaHandlerLookup(ServerRuntimeContext serverRuntimeContext) { this.serverRuntimeContext = serverRuntimeContext; } /** * looks into the stanza to see which handler is responsible, if any * @param stanza * @return NULL, if no handler could be */ @Override public StanzaHandler getHandler(Stanza stanza) { if (stanza == null) return null; // allow extensions to override default handling StanzaHandler stanzaHandler = getHandlerForElement(stanza, stanza); if(stanzaHandler != null) { return stanzaHandler; } else { String name = stanza.getName(); if ("xml".equals(name)) { return new XMLPrologHandler(); } else if ("stream".equals(name)) { return new StreamStartHandler(); } else if ("verify".equals(name)) { return new DbVerifyHandler(); } else if ("result".equals(name)) { return new DbResultHandler(); } else if (iqHandler.verify(stanza)) { return getIQHandler(stanza); } else if (messageHandler.verify(stanza)) { return getMessageHandler(stanza); } else if (presenceHandler.verify(stanza)) { return getPresenceHandler(stanza); } else { // ... and if we could not resolve and it's a core stanza, we can safely return an error if (XMPPCoreStanza.getWrapper(stanza) != null) return SERVICE_UNAVAILABLE_STANZA_ERROR_HANDLER; else return null; } } } private StanzaHandler getPresenceHandler(Stanza stanza) { return presenceHandler; } private StanzaHandler getMessageHandler(Stanza stanza) { return messageHandler; } private StanzaHandler getIQHandler(Stanza stanza) { StanzaHandler handlerForElement = null; Entity to = stanza.getTo(); Entity serverEntity = (serverRuntimeContext == null) ? null : serverRuntimeContext.getServerEnitity(); boolean isAddressedToServerOrComponent = (to == null || (!to.isNodeSet() && !to.isResourceSet())); boolean isAddressedToComponent = (to != null) && isAddressedToServerOrComponent && serverEntity != null && (!serverEntity.equals(to)); boolean isAddressedToServer = (to == null) || (isAddressedToServerOrComponent && !isAddressedToComponent); // The following cases must be properly handled: // 1. IQ disco stanza always handled by disco subsystem, not addressee // 2. to = someone@vysper.org => relay // 3. to = vysper.org => service unavailable // 4. to = component.vysper.org => relay // if no specialized handler can be identified, return general handler (relay) StanzaHandler resolvedHandler = null; if (stanza.getVerifier().subElementsPresentExact(1)) { XMLElement firstInnerElement = stanza.getFirstInnerElement(); handlerForElement = getHandlerForElement(stanza, firstInnerElement); if (handlerForElement != null) resolvedHandler = handlerForElement; if (resolvedHandler == null && isAddressedToServer && XMPPCoreStanza.getWrapper(stanza) != null) resolvedHandler = SERVICE_UNAVAILABLE_STANZA_ERROR_HANDLER; } if (resolvedHandler == null) resolvedHandler = iqHandler; return resolvedHandler; } }