View Javadoc

1   /*
2    *  Copyright 2004-2006 Stefan Reuter
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   *
16   */
17  package org.asteriskjava.live.internal;
18  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import org.asteriskjava.live.AgentState;
25  import org.asteriskjava.live.AsteriskAgent;
26  import org.asteriskjava.live.ManagerCommunicationException;
27  import org.asteriskjava.manager.ResponseEvents;
28  import org.asteriskjava.manager.action.AgentsAction;
29  import org.asteriskjava.manager.event.AgentCallbackLoginEvent;
30  import org.asteriskjava.manager.event.AgentCallbackLogoffEvent;
31  import org.asteriskjava.manager.event.AgentCalledEvent;
32  import org.asteriskjava.manager.event.AgentCompleteEvent;
33  import org.asteriskjava.manager.event.AgentConnectEvent;
34  import org.asteriskjava.manager.event.AgentLoginEvent;
35  import org.asteriskjava.manager.event.AgentLogoffEvent;
36  import org.asteriskjava.manager.event.AgentsEvent;
37  import org.asteriskjava.manager.event.ManagerEvent;
38  import org.asteriskjava.util.Log;
39  import org.asteriskjava.util.LogFactory;
40  
41  /**
42   * Manages all events related to agents on Asterisk server. For correct work
43   * ensure enabled AgentCalledEvents. You have to set
44   * <code>eventwhencalled = yes</code> in <code>queues.conf</code>.
45   *
46   * @author <a href="mailto:patrick.breucking{@nospam}gonicus.de">Patrick
47   *         Breucking</a>
48   * @version $Id$
49   * @since 0.3.1
50   */
51  public class AgentManager
52  {
53  
54      private final Log logger = LogFactory.getLog(this.getClass());
55  
56      private final AsteriskServerImpl server;
57  
58      /**
59       * A Map of agents by thier agentId.
60       */
61      private final Map<String, AsteriskAgentImpl> agents;
62  
63      /**
64       * A Map of agent in state RINGING by the caller id. Needed to return agent
65       * into idle state, if call was not conneted.
66       */
67      private final Map<String, AsteriskAgentImpl> ringingAgents;
68  
69      AgentManager(AsteriskServerImpl asteriskServerImpl)
70      {
71          this.server = asteriskServerImpl;
72          agents = new HashMap<String, AsteriskAgentImpl>();
73          ringingAgents = new HashMap<String, AsteriskAgentImpl>();
74      }
75  
76      /**
77       * Retrieves all agents registered at Asterisk server by sending an
78       * AgentsAction.
79       *
80       * @throws ManagerCommunicationException if communication with Asterisk
81       *                                       server fails.
82       */
83      void initialize() throws ManagerCommunicationException
84      {
85          ResponseEvents re;
86  
87          re = server.sendEventGeneratingAction(new AgentsAction());
88  
89          for (ManagerEvent event : re.getEvents())
90          {
91              if (event instanceof AgentsEvent)
92              {
93                  System.out.println(event);
94                  handleAgentsEvent((AgentsEvent) event);
95              }
96          }
97      }
98  
99      void disconnected()
100     {
101         synchronized (agents)
102         {
103             agents.clear();
104         }
105     }
106 
107     /**
108      * On AgentsEvent create a new Agent.
109      *
110      * @param event generated by Asterisk server.
111      */
112     void handleAgentsEvent(AgentsEvent event)
113     {
114         AsteriskAgentImpl agent = new AsteriskAgentImpl(server,
115                 event.getName(), "Agent/" + event.getAgent(), AgentState.valueOf(event.getStatus()));
116         logger.info("Adding agent " + agent.getName() + "(" + agent.getAgentId() + ")");
117 
118         addAgent(agent);
119     }
120 
121     /**
122      * Add a new agent to the manager.
123      *
124      * @param agent agent to add.
125      */
126     private void addAgent(AsteriskAgentImpl agent)
127     {
128         synchronized (agents)
129         {
130             agents.put(agent.getAgentId(), agent);
131         }
132         server.fireNewAgent(agent);
133     }
134 
135     /**
136      * Return the requested agent.
137      *
138      * @param agentId identifier for agent
139      * @return the requested agent
140      */
141     AsteriskAgentImpl getAgentByAgentId(String agentId)
142     {
143         synchronized (agents)
144         {
145             return agents.get(agentId);
146         }
147     }
148 
149     /**
150      * Update state if agent was called.
151      *
152      * @param event
153      */
154     void handleAgentCalledEvent(AgentCalledEvent event)
155     {
156         AsteriskAgentImpl agent = getAgentByAgentId(event.getAgentCalled());
157         if (agent == null)
158         {
159             logger.error("Ignored AgentCalledEvent for unknown agent " + event.getAgentCalled());
160             return;
161         }
162         updateRingingAgents(event.getChannelCalling(), agent);
163         updateAgentState(agent, AgentState.AGENT_RINGING);
164     }
165 
166     /**
167      * Set state of agent.
168      *
169      * @param agent
170      */
171     private void updateAgentState(AsteriskAgentImpl agent, AgentState newState)
172     {
173         logger.info("Set state of agent " + agent.getAgentId() + " to " + newState);
174         synchronized (agent)
175         {
176             agent.updateState(newState);
177         }
178     }
179 
180     /**
181      * Updates state of agent, if the call in a queue was redirect to the next
182      * agent because the ringed agent doesn't answer the call. After reset
183      * state, put the next agent in charge.
184      *
185      * @param channelCalling
186      * @param agent
187      */
188     private void updateRingingAgents(String channelCalling, AsteriskAgentImpl agent)
189     {
190         synchronized (ringingAgents)
191         {
192             if (ringingAgents.containsKey(channelCalling))
193             {
194                 updateAgentState(ringingAgents.get(channelCalling), AgentState.AGENT_IDLE);
195             }
196             ringingAgents.put(channelCalling, agent);
197         }
198     }
199 
200     /**
201      * Update state if agent was connected to channel.
202      *
203      * @param event
204      */
205     void handleAgentConnectEvent(AgentConnectEvent event)
206     {
207         AsteriskAgentImpl agent = getAgentByAgentId(event.getChannel());
208         if (agent == null)
209         {
210             logger.error("Ignored AgentConnectEvent for unknown agent " + event.getChannel());
211             return;
212         }
213         agent.updateState(AgentState.AGENT_ONCALL);
214     }
215     
216     /**
217      * Change state if agent logs in.
218      *
219      * @param event
220      */
221     void handleAgentLoginEvent(AgentLoginEvent event)
222     {
223         AsteriskAgentImpl agent = getAgentByAgentId("Agent/" + event.getAgent());
224         if (agent == null)
225         {
226             synchronized (agents)
227             {
228                 logger.error("Ignored AgentLoginEvent for unknown agent "
229                                 + event.getAgent() + ". Agents: " + agents.values().toString());
230 
231             }
232             return;
233         }
234         agent.updateState(AgentState.AGENT_IDLE);
235     }
236 
237     /**
238      * Change state if agent logs out.
239      *
240      * @param event
241      */
242     void handleAgentLogoffEvent(AgentLogoffEvent event)
243     {
244         AsteriskAgentImpl agent = getAgentByAgentId("Agent/" + event.getAgent());
245         if (agent == null)
246         {
247             logger.error("Ignored AgentLogoffEvent for unknown agent "
248                     + event.getAgent() + ". Agents: "
249                     + agents.values().toString());
250             return;
251         }
252         agent.updateState(AgentState.AGENT_LOGGEDOFF);
253     }
254 
255     /**
256      * Change state if agent logs in.
257      *
258      * @param event
259      */
260     void handleAgentCallbackLoginEvent(AgentCallbackLoginEvent event)
261     {
262         AsteriskAgentImpl agent = getAgentByAgentId("Agent/" + event.getAgent());
263         if (agent == null)
264         {
265             synchronized (agents)
266             {
267                 logger.error("Ignored AgentCallbackLoginEvent for unknown agent "
268                                 + event.getAgent() + ". Agents: " + agents.values().toString());
269 
270             }
271             return;
272         }
273         agent.updateState(AgentState.AGENT_IDLE);
274     }
275 
276     /**
277      * Change state if agent logs out.
278      *
279      * @param event
280      */
281     void handleAgentCallbackLogoffEvent(AgentCallbackLogoffEvent event)
282     {
283         AsteriskAgentImpl agent = getAgentByAgentId("Agent/" + event.getAgent());
284         if (agent == null)
285         {
286             logger.error("Ignored AgentCallbackLogoffEvent for unknown agent "
287                     + event.getAgent() + ". Agents: "
288                     + agents.values().toString());
289             return;
290         }
291         agent.updateState(AgentState.AGENT_LOGGEDOFF);
292 
293     }
294 
295     /**
296      * Return all agents registered at Asterisk server.
297      *
298      * @return a collection of all agents.
299      */
300     Collection<AsteriskAgent> getAgents()
301     {
302         Collection<AsteriskAgent> copy;
303 
304         synchronized (agents)
305         {
306             copy = new ArrayList<AsteriskAgent>(agents.values());
307         }
308         return copy;
309     }
310 
311     /**
312      * Change state if connected call was terminated.
313      *
314      * @param event
315      */
316     void handleAgentCompleteEvent(AgentCompleteEvent event)
317     {
318         AsteriskAgentImpl agent = getAgentByAgentId(event.getChannel());
319         if (agent == null)
320         {
321             logger.error("Ignored AgentCompleteEvent for unknown agent " + event.getChannel());
322             return;
323         }
324         agent.updateState(AgentState.AGENT_IDLE);
325     }
326 }