www.pudn.com > d4j.zip > Call.java


// Call: Model a basic call 
// $Id: Call.java,v 1.8 2003/11/13 11:34:59 cgm8 Exp $ 
/*  
 * Copyright (c) 1999 Carlos G Mendioroz. 
 * 
 *  This file is part of D4J. 
 * 
 *  D4J is free software; you can redistribute it and/or 
 *  modify it under the terms of the GNU Lesser General Public 
 *  License as published by the Free Software Foundation; either 
 *  version 2 of the License, or (at your option) any later version. 
 *   
 *  D4J is distributed in the hope that it will be useful, 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 *  Lesser General Public License for more details. 
 *   
 *  You should have received a copy of the GNU Lesser General Public 
 *  License along with this library; if not, write to the 
 *  Free Software Foundation, Inc., 59 Temple Place - Suite 330, 
 *  Boston, MA  02111-1307, USA. 
 * 
 * Report problems and direct all questions to: 
 * 
 *	tron@acm.org 
 */ 
package local.dialogic; 
import java.util.*; 
 
/** 
 * Call models a call, inbound or outbound, from the time  
 * the call exists in any way (remote line seizure for incoming 
 * calls, call placement in outgoing calls) upto call disposal, 
 * that may be well after call tear down. 
 * Channels are responsible for call creation for incoming calls 
 * via the Call(Channel) method, whether Call(number) is 
 * used for outbound call setup, using previously appointed 
 * channels for call placement. 
 */ 
 
public class Call extends java.lang.Object 
{ 
    // Id engine 
    static Object lastIdLock = new Object(); 
    static long lastId = 0; 
    // hash of groups(Vectors) of Channels 
    static Hashtable outChannels = new Hashtable();  
    // external logger (CDR ?) 
    static CallLogger logger = null; 
     
    // variables 
    long id; 
    Channel channel; 
    long startTime = 0; 
    long connectTime = 0; 
    long endTime = 0; 
 
    // To be defined how 
    String dialedNumber = null; // not null implies outgoing 
    String ani = null; 
    String dnis = null;         // not null implies incoming ? 
    String caller = null;       // Originating endpoint 
    int pulses = 0; 
     
    // External object for easy access/log 
    Object reference = null; 
     
    // Still some thinking needed 
    int state = 0; 
    public static final int NULL = 0; 
    public static final int INITIATED = 1; // AKA dialing 
    public static final int ALERTING = 2;  // AKA ringing 
    public static final int QUEUED = 3; 
    public static final int CONNECTED = 4; // AKA talking 
    public static final int HOLD = 5; 
    public static final int FAILED = 6; 
     
    // Accessors 
    public long id() { return id; } 
    public Channel channel() { return channel; } 
    public long startTime() { return startTime; } 
    public long connectTime() { return connectTime; } 
    public long endTime() { return endTime; } 
    public String dnis() { return dnis; } 
    public int getState() { return state; } 
    public Object reference() { return reference; } 
    public String dialedNumber() { return dialedNumber; } 
    public String caller() { return caller; } 
     
     
    // Incoming call creation 
    Call(Channel aChannel) { 
        channel = aChannel; 
        startTime = new Date().getTime(); 
        synchronized(lastIdLock) { 
            id = ++lastId; 
        } 
        state = INITIATED; 
    } 
     
    // Outgoing call setup 
    public Call(String number) { 
        Vector group = (Vector)outChannels.get(""); 
        if (group == null) { 
            // No hope, no channels 
            throw new RuntimeException("No outgoing channels available!"); 
        } 
        // XXX Here to implement outgoing policy, if any 
        Channel ch = null; 
        getChannel: 
        while (true) { 
            for (int i = 0; i < group.size(); i++) { 
                ch = (Channel)group.elementAt(i); 
                synchronized(ch) { 
                    if (ch.getState() == Channel.FREE) { 
                        // Ok! 
                        ch.setState(Channel.OUTGOING); 
                        break getChannel; 
                    } 
                } 
            } 
            // No channels, let caller decide... 
            throw new RuntimeException("No outgoing channels available!"); 
        } 
        setCall(number, ch); 
    } 
 
    public Call(String number, String groupId) { 
        Vector group = (Vector)outChannels.get(groupId); 
        if (group == null) { 
            // No hope, no channels 
            throw new RuntimeException("No outgoing channels available!"); 
        } 
        // XXX Here to implement outgoing policy, if any 
        Channel ch = null; 
        getChannel: 
        while (true) { 
            for (int i = 0; i < group.size(); i++) { 
                ch = (Channel)group.elementAt(i); 
                synchronized(ch) { 
                    if (ch.getState() == Channel.FREE) { 
                        // Ok! 
                        ch.setState(Channel.OUTGOING); 
                        break getChannel; 
                    } 
                } 
            } 
            // No channels, let caller decide... 
            throw new RuntimeException("No outgoing channels available!"); 
        } 
        setCall(number, ch); 
    } 
         
    public Call(String number, Channel ch) { 
        boolean ok = false; 
        synchronized(ch) { 
            if (ch.getState() == Channel.FREE) { 
                // Ok! 
                ch.setState(Channel.OUTGOING); 
                ok = true; 
            } 
        } 
        if (!ok) 
            throw new RuntimeException("Channel not available!"); 
        setCall(number, ch); 
    } 
         
    private void setCall(String number, Channel ch) { 
        this.startTime = System.currentTimeMillis(); 
        this.channel = ch; 
        this.dialedNumber = number; 
        this.state = INITIATED; 
        try { 
            ch.dial(this, number); 
        } catch (ChannelException ce) { 
            // This call never existed ??? 
            this.channel = null; 
            ch.clear(); 
            this.state = FAILED; 
            throw ce; 
        } 
        synchronized(lastIdLock) { 
            id = ++lastId; 
        } 
    } 
     
    // Outgoing calls channel appoint 
    public static void setDialout(Channel aChannel) 
    { 
        setDialout(aChannel, ""); 
    } 
     
    public static void setDialout(Channel aChannel, String groupId) 
    { 
        Vector group = (Vector)outChannels.get(groupId); 
        if (group == null) { 
            group = new Vector(); 
            outChannels.put(groupId, group); 
        } 
        group.addElement(aChannel); 
    } 
     
    // Caller identification 
    public void setCaller(String aCaller) { 
        if (caller == null) // Kind of protect messing with it... 
            caller = aCaller; 
    } 
     
    // Reference handling 
    public void setReference(Object anObject) { 
        reference = anObject; 
    } 
     
    // Logger interface 
    public static void setLogger(CallLogger aLogger) { 
        logger = aLogger; 
    } 
     
    public void accept() { 
        if (state == INITIATED && dialedNumber == null) { 
            state = ALERTING; 
            channel.accept(); 
        } 
    } 
 
    public void accept(int rings) { 
        if (state == INITIATED && dialedNumber == null) { 
            state = ALERTING; 
            channel.accept(rings); 
            connectTime = new Date().getTime(); 
            state = CONNECTED; 
        } 
    } 
     
    public void answer() { 
        if ((state == ALERTING || state == INITIATED)  
            && dialedNumber == null) { 
            channel.answer(); 
            connectTime = new Date().getTime(); 
            state = CONNECTED; 
        } 
    } 
 
    public void answer(int rings) { 
        if ((state == ALERTING || state == INITIATED)  
            && dialedNumber == null) { 
            state = ALERTING; 
            channel.answer(rings); 
            connectTime = new Date().getTime(); 
            state = CONNECTED; 
        } 
    } 
 
    public void reject(int reason) { 
        if (state == INITIATED && dialedNumber == null) { 
            channel.reject(reason); 
            state = FAILED; 
        } 
    } 
     
    // local clearing 
    public void clear() { 
        if (channel != null) { 
            Channel c = channel; 
            drop(); 
            try { 
				c.clear(); 
            } catch (ChannelException ce){}; 
        } 
        state = NULL; 
    } 
     
    // remote connect 
    void connect() { 
    	connectTime = new Date().getTime(); 
    	state = CONNECTED; 
    } 
     
    // remote clearing 
	synchronized void drop() { 
        if (channel != null) { 
            try { 
              pulses = channel.pulses();  // Just in case 
            } catch (Exception x) { 
              ; 
            } 
            endTime = new Date().getTime(); 
            if (logger != null) { 
            	try { 
					logger.log(this); 
            	} catch(Exception e) { 
					e.printStackTrace(); 
            	} 
            } 
        } 
        channel = null; 
        state = NULL; 
    } 
         
    public String ani() { 
        if (ani == null && channel != null) { 
            ani = channel.ani(); 
        } 
        return ani; 
    } 
     
    public int pulses() { 
        if (channel != null) { 
            pulses = channel.pulses(); 
        } 
        return pulses; 
    } 
     
    public String toString() { 
        return "Call " + id; 
    } 
}