Package rocks.xmpp.extensions.rpc

Source Code of rocks.xmpp.extensions.rpc.RpcManager

/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Christian Schudt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

package rocks.xmpp.extensions.rpc;

import rocks.xmpp.core.Jid;
import rocks.xmpp.core.XmppException;
import rocks.xmpp.core.session.ExtensionManager;
import rocks.xmpp.core.session.SessionStatusEvent;
import rocks.xmpp.core.session.SessionStatusListener;
import rocks.xmpp.core.session.XmppSession;
import rocks.xmpp.core.stanza.IQEvent;
import rocks.xmpp.core.stanza.IQListener;
import rocks.xmpp.core.stanza.model.StanzaError;
import rocks.xmpp.core.stanza.model.client.IQ;
import rocks.xmpp.core.stanza.model.errors.InternalServerError;
import rocks.xmpp.extensions.rpc.model.Rpc;
import rocks.xmpp.extensions.rpc.model.Value;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
* This manager allows you to call remote procedures and handle incoming calls, if enabled.
* <p>
* By default this manager is disabled. If you want to support RPC (i.e. handle incoming calls), {@linkplain #setEnabled(boolean) enable} it and {@linkplain #setRpcHandler(RpcHandler) set a RPC handler}, which allows you to handle incoming calls.
* </p>
*
* @author Christian Schudt
* @see <a href="http://xmpp.org/extensions/xep-0009.html">XEP-0009: Jabber-RPC</a>
*/
public final class RpcManager extends ExtensionManager {

    private static final Logger logger = Logger.getLogger(RpcManager.class.getName());

    ExecutorService executorService;

    private RpcHandler rpcHandler;

    private RpcManager(final XmppSession xmppSession) {
        super(xmppSession, Rpc.NAMESPACE);

        executorService = Executors.newCachedThreadPool();

        // Reset the rpcHandler, when the connection is closed, to avoid memory leaks.
        xmppSession.addSessionStatusListener(new SessionStatusListener() {
            @Override
            public void sessionStatusChanged(SessionStatusEvent e) {
                if (e.getStatus() == XmppSession.Status.CLOSED) {
                    rpcHandler = null;
                    executorService.shutdown();
                }
            }
        });

        xmppSession.addIQListener(new IQListener() {
            @Override
            public void handle(final IQEvent e) {
                final IQ iq = e.getIQ();
                if (e.isIncoming() && isEnabled() && !e.isConsumed() && iq.getType() == IQ.Type.SET) {
                    Rpc rpc = iq.getExtension(Rpc.class);
                    // If there's an incoming RPC
                    if (rpc != null) {
                        synchronized (RpcManager.this) {
                            if (rpcHandler != null) {
                                final Rpc.MethodCall methodCall = rpc.getMethodCall();
                                final List<Value> parameters = new ArrayList<>();
                                for (Value parameter : methodCall.getParameters()) {
                                    parameters.add(parameter);
                                }
                                executorService.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            Value value = rpcHandler.process(iq.getFrom(), methodCall.getMethodName(), parameters);
                                            IQ result = iq.createResult();
                                            result.setExtension(new Rpc(value));
                                            xmppSession.send(result);
                                        } catch (RpcException e1) {
                                            IQ result = iq.createResult();
                                            result.setExtension(new Rpc(new Rpc.MethodResponse.Fault(e1.getFaultCode(), e1.getFaultString())));
                                            xmppSession.send(result);
                                        } catch (Throwable e1) {
                                            logger.log(Level.WARNING, e1.getMessage(), e1);
                                            xmppSession.send(iq.createError(new StanzaError(new InternalServerError())));
                                        }
                                    }
                                });
                                e.consume();
                            }
                        }
                    }
                }
            }
        });
    }

    /**
     * Calls a remote procedure.
     *
     * @param jid        The JID, which will receive the RPC.
     * @param methodName The method name.
     * @param parameters The parameters.
     * @return The result.
     * @throws rocks.xmpp.core.session.NoResponseException  If the entity did not respond.
     * @throws rocks.xmpp.core.stanza.model.StanzaException If the RPC returned with an XMPP stanza error.
     * @throws RpcException                                 If the RPC returned with an application-level error ({@code <fault/>} element).
     */
    public Value call(Jid jid, String methodName, Value... parameters) throws XmppException, RpcException {
        IQ result = xmppSession.query(new IQ(jid, IQ.Type.SET, new Rpc(methodName, parameters)));
        if (result != null) {
            Rpc rpc = result.getExtension(Rpc.class);
            if (rpc != null) {
                Rpc.MethodResponse methodResponse = rpc.getMethodResponse();
                if (methodResponse != null) {
                    if (methodResponse.getFault() != null) {
                        throw new RpcException(methodResponse.getFault().getFaultCode(), methodResponse.getFault().getFaultString());
                    }
                    return methodResponse.getResponse();
                }
            }
        }
        return null;
    }

    /**
     * Sets the RPC handler, which will handle RPCs.
     *
     * @param rpcHandler The RPC handler.
     */
    public synchronized void setRpcHandler(RpcHandler rpcHandler) {
        this.rpcHandler = rpcHandler;
        setEnabled(rpcHandler != null);
    }
}
TOP

Related Classes of rocks.xmpp.extensions.rpc.RpcManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.