Package org.asteriskjava.fastagi

Source Code of org.asteriskjava.fastagi.AsyncAgiServer

package org.asteriskjava.fastagi;

import org.asteriskjava.manager.ManagerEventListener;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.event.AsyncAgiEvent;
import org.asteriskjava.manager.event.RenameEvent;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
import org.asteriskjava.fastagi.internal.AgiChannelFactory;
import org.asteriskjava.fastagi.internal.AsyncAgiConnectionHandler;
import org.asteriskjava.fastagi.internal.DefaultAgiChannelFactory;

import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.RejectedExecutionException;

/**
* AGI server for AGI over the Manager API (AsyncAGI).<p>
* AsyncAGI is available since Asterisk 1.6.
*
* @since 1.0.0
*/
public class AsyncAgiServer extends AbstractAgiServer implements ManagerEventListener
{
    private final Log logger = LogFactory.getLog(getClass());
    private final Map<Integer, AsyncAgiConnectionHandler> connectionHandlers;

    /**
     * Creates a new AsyncAgiServer with a {@link DefaultAgiChannelFactory}.<p>
     * Note that you must set a {@link org.asteriskjava.fastagi.MappingStrategy} before using it.
     *
     * @see #setMappingStrategy(MappingStrategy)
     */
    public AsyncAgiServer()
    {
        this(new DefaultAgiChannelFactory());
    }

    /**
     * Creates a new AsyncAgiServer with a custom {@link AgiChannelFactory}.<p>
     * Note that you must set a {@link org.asteriskjava.fastagi.MappingStrategy} before using it.
     *
     * @param agiChannelFactory The factory to use for creating new AgiChannel instances.
     * @see #setMappingStrategy(MappingStrategy)
     * @since 1.0.0
     */
    public AsyncAgiServer(AgiChannelFactory agiChannelFactory)
    {
        super(agiChannelFactory);
        this.connectionHandlers = new HashMap<Integer, AsyncAgiConnectionHandler>();
    }

    /**
     * Creates a new AsyncAgiServer with the given MappingStrategy.<p>
     * Please note that Async AGI does not currently support passing a script name, so your
     * MappingStrategy must be aware that the {@link org.asteriskjava.fastagi.AgiRequest#getScript() script}
     * property of the AgiRequests will likely be <code>null</code>.
     *
     * @param mappingStrategy the MappingStrategy to use to determine which AGI script to run
     *                        for a certain request.
     */
    public AsyncAgiServer(MappingStrategy mappingStrategy)
    {
        this(mappingStrategy, new DefaultAgiChannelFactory());
        logger.debug("use default AgiChannelFactory");
    }

    /**
     * Creates a new AsyncAgiServer with the given MappingStrategy.<p>
     * Please note that Async AGI does not currently support passing a script name, so your
     * MappingStrategy must be aware that the {@link org.asteriskjava.fastagi.AgiRequest#getScript() script}
     * property of the AgiRequests will likely be <code>null</code>.
     *
     * @param mappingStrategy   the MappingStrategy to use to determine which AGI script to run
     *                          for a certain request.
     * @param agiChannelFactory The factory to use for creating new AgiChannel instances.
     */
    public AsyncAgiServer(MappingStrategy mappingStrategy, AgiChannelFactory agiChannelFactory)
    {
        this(agiChannelFactory);
        setMappingStrategy(mappingStrategy);
    }

    /**
     * Creates a new AsyncAgiServer that will execute the given AGI script for every
     * request.<p>
     * Internally this constructor uses a {@link org.asteriskjava.fastagi.StaticMappingStrategy}.
     *
     * @param agiScript         the AGI script to execute.
     * @param agiChannelFactory The factory to use for creating new AgiChannel instances.
     */
    public AsyncAgiServer(AgiScript agiScript, AgiChannelFactory agiChannelFactory)
    {
        this(agiChannelFactory);
        setMappingStrategy(new StaticMappingStrategy(agiScript));
    }

    /**
     * Creates a new AsyncAgiServer that will execute the given AGI script for every
     * request.<p>
     * Internally this constructor uses a {@link org.asteriskjava.fastagi.StaticMappingStrategy}.
     *
     * @param agiScript the AGI script to execute.
     */
    public AsyncAgiServer(AgiScript agiScript)
    {
        this(agiScript, new DefaultAgiChannelFactory());
        logger.debug("use default AgiChannelFactory");
    }


    public void onManagerEvent(ManagerEvent event)
    {
        if (event instanceof AsyncAgiEvent)
        {
            handleAsyncAgiEvent((AsyncAgiEvent) event);
        }
        else if (event instanceof RenameEvent)
        {
            handleRenameEvent((RenameEvent) event);
        }
    }

    private void handleAsyncAgiEvent(AsyncAgiEvent asyncAgiEvent)
    {
        final ManagerConnection connection;
        final String channelName;
        final AsyncAgiConnectionHandler connectionHandler;

        connection = (ManagerConnection) asyncAgiEvent.getSource();
        channelName = asyncAgiEvent.getChannel();

        if (asyncAgiEvent.isStart())
        {
            connectionHandler = new AsyncAgiConnectionHandler(getMappingStrategy(), asyncAgiEvent, this.getAgiChannelFactory());
            setConnectionHandler(connection, channelName, connectionHandler);
            try
            {
                execute(connectionHandler);
            }
            catch (RejectedExecutionException e)
            {
                logger.warn("Execution was rejected by pool. Try to increase the pool size.");
                // release resources if execution was rejected due to the pool size
                connectionHandler.release();
            }
        }
        else
        {
            connectionHandler = getConnectionHandler(connection, channelName);
            if (connectionHandler == null)
            {
                logger.info("No AsyncAgiConnectionHandler registered for channel " + channelName + ": Ignoring AsyncAgiEvent");
                return;
            }

            if (asyncAgiEvent.isExec())
            {
                connectionHandler.onAsyncAgiExecEvent(asyncAgiEvent);
            }
            else if (asyncAgiEvent.isEnd())
            {
                connectionHandler.onAsyncAgiEndEvent(asyncAgiEvent);
                removeConnectionHandler(connection, channelName);
            }
            else
            {
                logger.warn("Ignored unknown AsyncAgiEvent of sub type '" + asyncAgiEvent.getSubEvent() + "'");
            }
        }
    }

    private void handleRenameEvent(RenameEvent renameEvent)
    {
        final ManagerConnection connection = (ManagerConnection) renameEvent.getSource();
        final AsyncAgiConnectionHandler connectionHandler = getConnectionHandler(connection, renameEvent.getChannel());

        if (connectionHandler == null)
        {
            return;
        }

        removeConnectionHandler(connection, renameEvent.getChannel());
        setConnectionHandler(connection, renameEvent.getNewname(), connectionHandler);

        connectionHandler.updateChannelName(renameEvent.getNewname());
    }

    private AsyncAgiConnectionHandler getConnectionHandler(ManagerConnection connection, String channelName)
    {
        synchronized (connectionHandlers)
        {
            return connectionHandlers.get(calculateHashKey(connection, channelName));
        }
    }

    private void setConnectionHandler(ManagerConnection connection, String channelName, AsyncAgiConnectionHandler connectionHandler)
    {
        synchronized (connectionHandlers)
        {
            connectionHandlers.put(calculateHashKey(connection, channelName), connectionHandler);
        }
    }

    private void removeConnectionHandler(ManagerConnection connection, String channelName)
    {
        synchronized (connectionHandlers)
        {
            connectionHandlers.remove(calculateHashKey(connection, channelName));
        }
    }

    private Integer calculateHashKey(ManagerConnection connection, String channelName)
    {
        return connection.hashCode() * 31 + channelName.hashCode();
    }
}
TOP

Related Classes of org.asteriskjava.fastagi.AsyncAgiServer

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.