org.maodian.flyingcat.xmpp.state.DefaultXmppContext.java Source code

Java tutorial

Introduction

Here is the source code for org.maodian.flyingcat.xmpp.state.DefaultXmppContext.java

Source

/*
 * Copyright 2013 - 2013 Cole Wen
 *
 * 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.
 */
package org.maodian.flyingcat.xmpp.state;

import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;

import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.apache.commons.lang3.StringUtils;
import org.maodian.flyingcat.holder.XMLOutputFactoryHolder;
import org.maodian.flyingcat.im.IMException;
import org.maodian.flyingcat.im.IMSession;
import org.maodian.flyingcat.im.entity.sql.AccountEntity;
import org.maodian.flyingcat.im.entity.sql.ContactEntity;
import org.maodian.flyingcat.xmpp.GlobalContext;
import org.maodian.flyingcat.xmpp.codec.Encoder;
import org.maodian.flyingcat.xmpp.entity.JabberID;
import org.maodian.flyingcat.xmpp.entity.Presence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * @author Cole Wen
 * 
 */
public class DefaultXmppContext implements XmppContext {
    private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
    private final GlobalContext appCtx;
    private final IMSession imSession;
    private ChannelHandlerContext nettyCtx;
    private State state;
    private JabberID jid;
    private String streamTag;
    private XmppContextManager xmppCtxMgr;
    private Set<XmppContextListener> listeners;

    /**
     * @param nettyCtx
     * @param appCtx
     */
    public DefaultXmppContext(GlobalContext appCtx, IMSession imSession) {
        this.appCtx = appCtx;
        this.imSession = imSession;
        listeners = new CopyOnWriteArraySet<>();
        state = appCtx.getOpenStreamState();
    }

    @Override
    public void setState(State state) {
        this.state = state;
    }

    @Override
    public void setStreamTag(String streamTag) {
        this.streamTag = streamTag;
    }

    @Override
    public ChannelHandlerContext getNettyChannelHandlerContext() {
        return nettyCtx;
    }

    @Override
    public void setNettyChannelHandlerContext(ChannelHandlerContext nettyCtx) {
        this.nettyCtx = nettyCtx;
    }

    public void setXmppContextManger(XmppContextManager xmppCtxMgr) {
        this.xmppCtxMgr = xmppCtxMgr;
        listeners.add((XmppContextListener) this.xmppCtxMgr);
    }

    public void setListeners(Set<XmppContextListener> listeners) {
        this.listeners.addAll(listeners);
    }

    @Override
    public String wrapStreamTag(String xml) {
        return streamTag + xml;
    }

    @Override
    public void login(String username, String password) {
        try {
            preLogin();
            imSession.login(username, password);
            setJabberID(JabberID.fromString(username + "@localhost"));
            postLogin();
        } catch (IMException e) {
            throw new XmppException(e, SASLError.NOT_AUTHORIZED);
        }
    }

    private void preLogin() {
        for (XmppContextListener listener : listeners) {
            listener.onPreLogin(this);
        }
    }

    private void postLogin() {
        for (XmppContextListener listener : listeners) {
            listener.onPostLogin(this);
        }
    }

    /* (non-Javadoc)
     * @see org.maodian.flyingcat.xmpp.state.XmppContext#bindResource(java.lang.String)
     */
    @Override
    public void bind(String resource) {
        preBind();
        JabberID newJid = JabberID.createInstance(jid.getUid(), jid.getDomain(), resource);
        this.jid = newJid;
        postBind();
    }

    private void preBind() {

    }

    private void postBind() {
        for (XmppContextListener listener : listeners) {
            listener.onPostBind(this);
        }
    }

    @Override
    public void destroy() {
        preDestroy();
        if (imSession != null) {
            imSession.destroy();
        }
        postDestroy();
    }

    private void preDestroy() {
        for (XmppContextListener listener : listeners) {
            listener.onPreDestroy(this);
        }
    }

    private void postDestroy() {
        for (XmppContextListener listener : listeners) {
            listener.onPostDestroy(this);
        }
    }

    @Override
    public void parseXML(final String xml) {
        log.debug("{} SEND: {}", jid == null ? null : jid.toFullJID(), xml);
        Result result = state.step(this, xml);
        state = result.getNextState();
    }

    @Override
    public IMSession getIMSession() {
        return imSession;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.maodian.flyingcat.xmpp.state.XmppContext#getApplicationContext()
     */
    @Override
    public GlobalContext getGlobalContext() {
        return appCtx;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.maodian.flyingcat.xmpp.state.XmppContext#flush(java.lang.String)
     */
    @Override
    public void flush(String str) {
        if (StringUtils.isNotBlank(str)) {
            log.debug("{} RECEIVED: {}", jid == null ? null : jid.toFullJID(), str);
            nettyCtx.write(str).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
            nettyCtx.flush();
        }
    }

    private void setJabberID(JabberID jid) {
        this.jid = jid;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.maodian.flyingcat.xmpp.state.XmppContext#getJabberID()
     */
    @Override
    public JabberID getJabberID() {
        return jid;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.maodian.flyingcat.xmpp.state.XmppContext#send(org.maodian.flyingcat
     * .xmpp.entity.JabberID, java.lang.Object)
     */
    @Override
    public void send(JabberID to, Object payload) {
        AccountEntity ta = imSession.getAccountRepository().findByUid(to.getUid());
        if (ta == null) {
            throw new RuntimeException("User does not existed");
        }
        preSend(payload);
        xmppCtxMgr.transfer(getJabberID(), to, payload);
        postSend(payload);
    }

    private void preSend(Object payload) {

    }

    private void postSend(Object payload) {
        for (XmppContextListener listener : listeners) {
            listener.onPostSend(this, payload);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.maodian.flyingcat.xmpp.state.XmppContext#receive(org.maodian.flyingcat
     * .xmpp.entity.JabberID, java.lang.Object)
     */
    @Override
    public void receive(JabberID from, Object payload) {
        preReceive(payload);
        Encoder encoder = appCtx.getEncoder(payload.getClass());
        try (Writer writer = new StringWriter();) {
            XMLStreamWriter xmlsw = XMLOutputFactoryHolder.getXMLOutputFactory().createXMLStreamWriter(writer);
            encoder.encode(payload, xmlsw);
            flush(writer.toString());
            postReceive(payload);
        } catch (XMLStreamException | IOException e) {
            throw new RuntimeException("Error when receiving payload", e);
        }
    }

    private void preReceive(Object payload) {

    }

    private void postReceive(Object payload) {
        for (XmppContextListener listener : listeners) {
            listener.onPostReceive(this, payload);
        }
    }

    /* (non-Javadoc)
     * @see org.maodian.flyingcat.xmpp.state.XmppContext#broadcast(java.lang.Object)
     */
    @Override
    public void broadcastPresence() {
        AccountEntity owner = imSession.getAccountRepository().findByUid(jid.getUid());

        // broadcast availability to contacts
        Collection<ContactEntity> subscribers = imSession.getContactRepository().findByOwnerAndSubFrom(owner, true);
        for (ContactEntity su : subscribers) {
            JabberID to = JabberID.createInstance(su.getUid(), "localhost", null);
            Presence presence = new Presence();
            presence.setFrom(getJabberID());
            presence.setTo(to);
            xmppCtxMgr.transfer(getJabberID(), to, presence);
        }

        // broadcast to user's other availability resource
        JabberID to = JabberID.createInstance(getJabberID().getUid(), "localhost", null);
        Presence presence = new Presence();
        presence.setFrom(getJabberID());
        presence.setTo(to);
        send(to, presence);
    }
}