All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.asteriskjava.pbx.internal.activity.ParkActivityImpl Maven / Gradle / Ivy

There is a newer version: 3.41.0
Show newest version
package org.asteriskjava.pbx.internal.activity;

import org.asteriskjava.lock.Locker.LockCloser;
import org.asteriskjava.manager.TimeoutException;
import org.asteriskjava.pbx.*;
import org.asteriskjava.pbx.activities.ParkActivity;
import org.asteriskjava.pbx.asterisk.wrap.actions.RedirectAction;
import org.asteriskjava.pbx.asterisk.wrap.events.ManagerEvent;
import org.asteriskjava.pbx.asterisk.wrap.events.ParkedCallEvent;
import org.asteriskjava.pbx.asterisk.wrap.response.ManagerResponse;
import org.asteriskjava.pbx.internal.core.AsteriskPBX;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;

import java.io.IOException;
import java.util.HashSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * The ParkActivity is used by the AsteriksPBX implementation to park a channel.
 * The park activity expects two channels which are two legs legs of the same
 * call. The parkChannel will be redirect to the njr-park extension. The
 * hangupChannel (the second leg of the call) will be hung up. The (obvious?)
 * limitation is that we can't park something like a conference call as it has
 * more than two channels.
 *
 * @author bsutton
 */
public class ParkActivityImpl extends ActivityHelper implements ParkActivity {
    private static final Log logger = LogFactory.getLog(ParkActivityImpl.class);

    /**
     * call - the call which is being packed.
     */
    private final Call _call;

    /**
     * parkChannel - the channel from the above call which is going to be
     * parked. extension.
     */
    private final Channel _parkChannel;

    private volatile EndPoint _parkingLot;

    private final CountDownLatch _latch = new CountDownLatch(1);

    /*
     * @param call the that is being parked.
     * @param parkChannel the channel from the call which is the one which will
     * be parked. All other channels in the call will be hungup.
     */
    public ParkActivityImpl(final Call call, final Channel parkChannel, final ActivityCallback listener) {
        super("ParkActivity", listener);

        if (call == null) {
            throw new IllegalArgumentException("call may not be null");
        }
        if (parkChannel == null) {
            throw new IllegalArgumentException("parkChannel may not be null");
        }
        this._parkChannel = parkChannel;
        this._call = call;

        if (!this._call.contains(parkChannel))
            throw new IllegalArgumentException("The parkChannel must be from the call.");

        this.startActivity(true);
    }

    @Override
    public boolean doActivity() throws PBXException {
        boolean success = false;
        final AsteriskPBX pbx = (AsteriskPBX) PBXFactory.getActivePBX();

        ParkActivityImpl.logger.debug("*******************************************************************************");
        ParkActivityImpl.logger.info("***********                    begin park               ****************");
        ParkActivityImpl.logger.info("***********            " + this._parkChannel + "                 ****************");
        ParkActivityImpl.logger.debug("*******************************************************************************");

        try {
            final AsteriskSettings profile = PBXFactory.getActiveProfile();

            if (!pbx.waitForChannelToQuiescent(this._parkChannel, 3000))
                throw new PBXException("Channel: " + this._parkChannel + " cannot be parked as it is still in transition.");

            // The extension must be a non-qualified name as
            // otherwise it would be of the form DIALPLAN/njr-park
            final RedirectAction redirect = new RedirectAction(this._parkChannel, profile.getManagementContext(),
                    pbx.getExtensionPark(), 1);

            final ManagerResponse response = pbx.sendAction(redirect, 1000);
            if ((response != null) && (response.getResponse().compareToIgnoreCase("success") == 0)) {
                // Hangup the call as we have parked the other side of
                // the call.
                if (this._call.getDirection() == CallDirection.INBOUND) {
                    logger.warn("Hanging up");
                    pbx.hangup(this._call.getAcceptingParty());
                } else {
                    logger.warn("Hanging up");
                    pbx.hangup(this._call.getOriginatingParty());
                }
                success = true;
            }

        } catch (IllegalArgumentException | IllegalStateException | IOException | TimeoutException e) {
            ParkActivityImpl.logger.error(e, e);
            throw new PBXException(e);

        } finally {
            // we wait at most 2 seconds for the parking extension to
            // arrive.
            try {
                if (success) {
                    if (!this._latch.await(2, TimeUnit.SECONDS)) {
                        logger.warn("Timeout, continuing");
                    }
                }

                if (this._parkingLot == null) {
                    success = false;
                    ParkActivityImpl.logger.warn("ParkCallEvent not recieved within 2 seconds of parking call.");
                    this.setLastException(new PBXException("ParkCallEvent  not recieved within 2 seconds of parking call."));
                }
            } catch (final InterruptedException e) {
                ParkActivityImpl.logger.error(e, e);

            }

        }
        return success;
    }

    @Override
    public EndPoint getParkingLot() {
        return this._parkingLot;
    }

    @Override
    public HashSet> requiredEvents() {
        HashSet> required = new HashSet<>();

        required.add(ParkedCallEvent.class);

        return required;
    }

    @Override
    public void onManagerEvent(final ManagerEvent event) {
        try (LockCloser closer = this.withLock()) {
            assert event instanceof ParkedCallEvent : "Unexpected event";

            final ParkedCallEvent parkedEvent = (ParkedCallEvent) event;
            final AsteriskPBX pbx = (AsteriskPBX) PBXFactory.getActivePBX();

            this._parkingLot = pbx.buildEndPoint(TechType.LOCAL, parkedEvent.getExten());
            this._latch.countDown();
        }
    }

    @Override
    public ListenerPriority getPriority() {
        return ListenerPriority.NORMAL;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy