com.kixeye.kixmpp.handler.KixmppEventEngine.java Source code

Java tutorial

Introduction

Here is the source code for com.kixeye.kixmpp.handler.KixmppEventEngine.java

Source

package com.kixeye.kixmpp.handler;

/*
 * #%L
 * KIXMPP
 * %%
 * Copyright (C) 2014 KIXEYE, Inc
 * %%
 * Licensed 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.
 * #L%
 */

import io.netty.channel.Channel;

import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.fusesource.hawtdispatch.Dispatch;
import org.fusesource.hawtdispatch.DispatchQueue;
import org.fusesource.hawtdispatch.Task;
import org.jdom2.Element;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.kixeye.kixmpp.KixmppJid;
import com.kixeye.kixmpp.KixmppStreamEnd;
import com.kixeye.kixmpp.KixmppStreamStart;
import com.kixeye.kixmpp.tuple.Tuple;

/**
 * An event engine that uses a {@link DispatchQueue}.
 * 
 * @author ebahtijaragic
 */
public class KixmppEventEngine {
    private static final String HANDLER_WILDCARD = "*";

    private final ConcurrentHashMap<Tuple, Set<KixmppStanzaHandler>> stanzaHandlers = new ConcurrentHashMap<>();
    private final Set<KixmppConnectionHandler> connectionHandlers = Collections
            .newSetFromMap(new ConcurrentHashMap<KixmppConnectionHandler, Boolean>());
    private final Set<KixmppStreamHandler> streamHandlers = Collections
            .newSetFromMap(new ConcurrentHashMap<KixmppStreamHandler, Boolean>());
    private final Set<KixmppSessionHandler> sessionHandlers = Collections
            .newSetFromMap(new ConcurrentHashMap<KixmppSessionHandler, Boolean>());

    private final LoadingCache<String, DispatchQueue> queues = CacheBuilder.newBuilder()
            .expireAfterAccess(30, TimeUnit.SECONDS).build(new CacheLoader<String, DispatchQueue>() {
                public DispatchQueue load(String key) throws Exception {
                    return Dispatch.createQueue(key);
                }
            });

    /**
     * Publishes a stanza.
     * 
     * @param channel
     * @param stanza
     */
    public void publishStanza(Channel channel, Element stanza) {
        String to = stanza.getAttributeValue("to");

        DispatchQueue queue;

        try {
            if (to != null) {
                queue = queues.get("address:" + to);
            } else {
                queue = queues.get("channel:" + channel.hashCode());
            }
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        if (to != null) {
            Set<KixmppStanzaHandler> recipientHandlers = stanzaHandlers
                    .get(Tuple.from(stanza.getQualifiedName(), KixmppJid.fromRawJid(to)));

            if (recipientHandlers != null) {
                for (KixmppStanzaHandler handler : recipientHandlers) {
                    queue.execute(new ExecuteStanzaHandler(handler, channel, stanza));
                }
            }

            recipientHandlers = stanzaHandlers.get(Tuple.from(HANDLER_WILDCARD, KixmppJid.fromRawJid(to)));

            if (recipientHandlers != null) {
                for (KixmppStanzaHandler handler : recipientHandlers) {
                    queue.execute(new ExecuteStanzaHandler(handler, channel, stanza));
                }
            }
        }

        Set<KixmppStanzaHandler> globalHandlers = stanzaHandlers.get(Tuple.from(stanza.getQualifiedName()));

        if (globalHandlers != null) {
            for (KixmppStanzaHandler handler : globalHandlers) {
                queue.execute(new ExecuteStanzaHandler(handler, channel, stanza));
            }
        }

        globalHandlers = stanzaHandlers.get(Tuple.from(HANDLER_WILDCARD));

        if (globalHandlers != null) {
            for (KixmppStanzaHandler handler : globalHandlers) {
                queue.execute(new ExecuteStanzaHandler(handler, channel, stanza));
            }
        }
    }

    /**
     * Published an arbitrary task for serial execution.
     * 
     * @param jid
     * @param task
     */
    public void publishTask(KixmppJid jid, Task task) {
        DispatchQueue queue;

        try {
            if (jid != null) {
                queue = queues.get("address:" + jid.getFullJid());
            } else {
                queue = queues.get("default");
            }
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        queue.execute(task);
    }

    /**
     * Published an arbitrary task for serial execution.
     * 
     * @param channel
     * @param task
     */
    public void publishTask(Channel channel, Task task) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        queue.execute(task);
    }

    /**
     * Publishes that a channel has connected.
     * 
     * @param channel
     */
    public void publishConnected(Channel channel) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        for (KixmppConnectionHandler handler : connectionHandlers) {
            queue.execute(new ExecuteConnectionConnectedHandler(handler, channel));
        }
    }

    /**
     * Publishes that a channel has disconnected.
     * 
     * @param channel
     */
    public void publishDisconnected(Channel channel) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        for (KixmppConnectionHandler handler : connectionHandlers) {
            queue.execute(new ExecuteConnectionDisconnectedHandler(handler, channel));
        }
    }

    /**
     * Publishes a stream start event.
     * 
     * @param channel
     * @param streamStart
     */
    public void publishStreamStart(Channel channel, KixmppStreamStart streamStart) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        for (KixmppStreamHandler handler : streamHandlers) {
            queue.execute(new ExecuteStreamStartHandler(handler, channel, streamStart));
        }
    }

    /**
     * Publishes a stream end event.
     * 
     * @param channel
     * @param streamEnd
     */
    public void publishStreamEnd(Channel channel, KixmppStreamEnd streamEnd) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        for (KixmppStreamHandler handler : streamHandlers) {
            queue.execute(new ExecuteStreamEndHandler(handler, channel, streamEnd));
        }
    }

    /**
     * Publishes a session start event.
     *
     * @param channel
     */
    public void publishSessionStart(Channel channel) {
        DispatchQueue queue;

        try {
            queue = queues.get("channel:" + channel.hashCode());
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        for (KixmppSessionHandler handler : sessionHandlers) {
            queue.execute(new ExecuteSessionStartHandler(handler, channel));
        }
    }

    /**
     * Registers a handler to listen to connection events.
     * 
     * @param handler
     */
    public void registerConnectionHandler(KixmppConnectionHandler handler) {
        connectionHandlers.add(handler);
    }

    /**
     * Unregisters a connection handler.
     * 
     * @param handler
     */
    public void unregisterConnectionHandler(KixmppConnectionHandler handler) {
        connectionHandlers.remove(handler);
    }

    /**
     * Registers a stream handler.
     *
     * @param handler
     */
    public void registerStreamHandler(KixmppStreamHandler handler) {
        streamHandlers.add(handler);
    }

    /**
     * Unregisters a stream handler.
     *
     * @param handler
     */
    public void unregisterStreamHandler(KixmppStreamHandler handler) {
        streamHandlers.remove(handler);
    }

    /**
     * Registers a session handler.
     *
     * @param handler
     */
    public void registerSessionHandler(KixmppSessionHandler handler) {
        sessionHandlers.add(handler);
    }

    /**
     * Unregisters a session handler.
     *
     * @param handler
     */
    public void unregisterSessionHandler(KixmppSessionHandler handler) {
        sessionHandlers.remove(handler);
    }

    /**
     * Registers a stanza handler.
     * 
     * @param qualifiedName
     * @param jid
     * @param handler
     */
    public void registerStanzaHandler(KixmppJid jid, String qualifiedName, KixmppStanzaHandler handler) {
        Tuple key = Tuple.from(qualifiedName, jid);

        Set<KixmppStanzaHandler> handlers = stanzaHandlers.get(key);

        if (handlers == null) {
            Set<KixmppStanzaHandler> newHandlers = Collections
                    .newSetFromMap(new ConcurrentHashMap<KixmppStanzaHandler, Boolean>());

            handlers = stanzaHandlers.putIfAbsent(key, newHandlers);

            if (handlers == null) {
                handlers = newHandlers;
            }
        }

        handlers.add(handler);
    }

    /**
     * Registers a stanza handler.
     * 
     * @param jid
     * @param handler
     */
    public void registerStanzaHandler(KixmppJid jid, KixmppStanzaHandler handler) {
        registerStanzaHandler(jid, HANDLER_WILDCARD, handler);
    }

    /**
     * Registers a stanza handler.
     * 
     * @param handler
     */
    public void registerGlobalStanzaHandler(String qualifiedName, KixmppStanzaHandler handler) {
        Tuple key = Tuple.from(qualifiedName);

        Set<KixmppStanzaHandler> handlers = stanzaHandlers.get(key);

        if (handlers == null) {
            Set<KixmppStanzaHandler> newHandlers = Collections
                    .newSetFromMap(new ConcurrentHashMap<KixmppStanzaHandler, Boolean>());

            handlers = stanzaHandlers.putIfAbsent(key, newHandlers);

            if (handlers == null) {
                handlers = newHandlers;
            }
        }

        handlers.add(handler);
    }

    /**
     * Registers a stanza handler.
     * 
     * @param handler
     */
    public void registerGlobalStanzaHandler(KixmppStanzaHandler handler) {
        registerGlobalStanzaHandler(HANDLER_WILDCARD, handler);
    }

    /**
     * Unregisters a stanza handler.
     * 
     * @param jid
     * @param qualifiedName
     * @param handler
     */
    public void unregisterStanzaHandler(KixmppJid jid, String qualifiedName, KixmppStanzaHandler handler) {
        Set<KixmppStanzaHandler> handlers = stanzaHandlers.get(Tuple.from(qualifiedName, jid));

        if (handlers != null) {
            handlers.remove(handler);
        }
    }

    /**
     * Unregisters a stanza handler.
     * 
     * @param jid
     * @param handler
     */
    public void unregisterStanzaHandler(KixmppJid jid, KixmppStanzaHandler handler) {
        unregisterStanzaHandler(jid, HANDLER_WILDCARD, handler);
    }

    /**
     * Unregisters a stanza handler.
     * 
     * @param qualifiedName
     * @param handler
     */
    public void unregisterGlobalStanzaHandler(String qualifiedName, KixmppStanzaHandler handler) {
        Set<KixmppStanzaHandler> handlers = stanzaHandlers.get(Tuple.from(qualifiedName));

        if (handlers != null) {
            handlers.remove(handler);
        }
    }

    /**
     * Unregisters a stanza handler.
     * 
     * @param handler
     */
    public void unregisterGlobalStanzaHandler(KixmppStanzaHandler handler) {
        unregisterGlobalStanzaHandler(HANDLER_WILDCARD, handler);
    }

    /**
     * Unregisters all the handlers.
     */
    public void unregisterAll() {
        stanzaHandlers.clear();
        connectionHandlers.clear();
        streamHandlers.clear();
        sessionHandlers.clear();
    }

    private static class ExecuteStanzaHandler extends Task {
        private final KixmppStanzaHandler handler;
        private final Channel channel;
        private final Element stanza;

        public ExecuteStanzaHandler(KixmppStanzaHandler handler, Channel channel, Element stanza) {
            this.handler = handler;
            this.channel = channel;
            this.stanza = stanza;
        }

        public void run() {
            handler.handle(channel, stanza);
        }
    }

    private static class ExecuteConnectionConnectedHandler extends Task {
        private final KixmppConnectionHandler handler;
        private final Channel channel;

        public ExecuteConnectionConnectedHandler(KixmppConnectionHandler handler, Channel channel) {
            this.handler = handler;
            this.channel = channel;
        }

        public void run() {
            handler.handleConnected(channel);
        }
    }

    private static class ExecuteConnectionDisconnectedHandler extends Task {
        private final KixmppConnectionHandler handler;
        private final Channel channel;

        public ExecuteConnectionDisconnectedHandler(KixmppConnectionHandler handler, Channel channel) {
            this.handler = handler;
            this.channel = channel;
        }

        public void run() {
            handler.handleDisconnected(channel);
        }
    }

    private static class ExecuteStreamStartHandler extends Task {
        private final KixmppStreamHandler handler;
        private final Channel channel;
        private final KixmppStreamStart start;

        public ExecuteStreamStartHandler(KixmppStreamHandler handler, Channel channel, KixmppStreamStart start) {
            this.handler = handler;
            this.channel = channel;
            this.start = start;
        }

        public void run() {
            handler.handleStreamStart(channel, start);
        }
    }

    private static class ExecuteStreamEndHandler extends Task {
        private final KixmppStreamHandler handler;
        private final Channel channel;
        private final KixmppStreamEnd end;

        public ExecuteStreamEndHandler(KixmppStreamHandler handler, Channel channel, KixmppStreamEnd end) {
            this.handler = handler;
            this.channel = channel;
            this.end = end;
        }

        public void run() {
            handler.handleStreamEnd(channel, end);
        }
    }

    private static class ExecuteSessionStartHandler extends Task {
        private final KixmppSessionHandler handler;
        private final Channel channel;

        public ExecuteSessionStartHandler(KixmppSessionHandler handler, Channel channel) {
            this.handler = handler;
            this.channel = channel;
        }

        public void run() {
            handler.handleSessionStart(channel);
        }
    }
}