| /* |
| * 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.getServerEntity(); |
| 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; |
| } |
| } |