Monday, January 19, 2015

JPA with Vaadin

To create a JPA (Java Persistence API) app, do the following:

  • create persistence.xml under WEB-INF/classes/META-INF in eclipse
  • create POJO (AgentStatus in this example) with annotations
  • create a JPA container in the code and call it refresh method
  • ensure to have vaadin-jpacontainer-3.1.1.jar and hibernate-entitymanager-4.1.4.Final.jar
put persistence.xml under WEB-INF/classes/META-INF
<?xml version="1.0" encoding="UTF-8"?>
    <persistence
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
    version="1.0">
    <persistence-unit name="agent-status">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>net.mycompany.tps.blvd.domain.AgentStatus</class>
        
    <properties>
    <!--
    <property name="hibernate.ejb.cfgfile" value="/hibernate.cfg.xml"/>
    <property name="hibernate.hbm2ddl.auto" value="create"/>
    -->
    <property name="hibernate.archive.autodetection" value="class, hbm"/>
    <property name="hibernate.show_sql" value="true"/>
    <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
    <property name="hibernate.connection.password" value="tm211"/>
    <property name="hibernate.connection.url" value="jdbc:mysql://tpsdbs.mycompany.net/blvd"/>
    <!--  <property name="hibernate.connection.url" value="jdbc:mysql://solo.mycompany.net/blvd"/> -->
    <property name="hibernate.connection.username" value="tps_mon"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
    <property name="hibernate.c3p0.min_size" value="5"/>
    <property name="hibernate.c3p0.max_size" value="20"/>
    <property name="hibernate.c3p0.timeout" value="300"/>
    <property name="hibernate.c3p0.max_statememycompany" value="50"/>
    <property name="hibernate.c3p0.idle_test_period" value="3000"/>
    </properties>
    </persistence-unit>
    </persistence>

AgentStatus.java

package net.mycompany.tps.blvd.domain;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;

import net.mycompany.tps.blvd.dao.LaborTypeDao;
import net.mycompany.tps.blvd.dao.UsersDao;
import net.mycompany.tps.blvd.util.HibernateUtil;
@Entity
@Table(name="agent_status")
public class AgentStatus implements Serializable {
 private static final long serialVersionUID = 1L;
 
 @Id
 private int id;
 @Transient
 private String ani;
 private String globalId;
 @Column(name="last_call")
 private Date lastCall;
 @Column(name="login_time")
 private Date loginTime;
 @Column(name="login_type")
 private String loginType; // one of 1ON1, GROUP, LOGGEDOFF, SUPER
 private String paused; //one of TRUE/FALSE 
 private Date timestamp;
 private String hostname;
 private String channel;
 
 public static String LOGIN_1ON1 = "1ON1";
 public static String LOGIN_GROUP = "GROUP";
 public static String LOGGED_OFF = "LOGGEDOFF";
 public static String LOGIN_SUPER = "SUPER";
 
 @Transient
 private String agentName;
 @Transient
 private LaborType laborType;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 @Transient
 public String getAni() {
  return ani;
 }
 @Transient
 public void setAni(String ani) {
  this.ani = ani;
 }
 public String getGlobalId() {
  return globalId;
 }
 public void setGlobalId(String globalId) {
  this.globalId = globalId;
 }
 public Date getLastCall() {
  return lastCall;
 }
 public void setLastCall(Date lastCall) {
  this.lastCall = lastCall;
 }
 public Date getLoginTime() {
  return loginTime;
 }
 public void setLoginTime(Date loginTime) {
  this.loginTime = loginTime;
 }
 public String getLoginType() {
  return loginType;
 }
 public void setLoginType(String loginType) {
  this.loginType = loginType;
 }
 public String getPaused() {
  return paused;
 }
 public void setPaused(String paused) {
  this.paused = paused;
 }
 public Date getTimestamp() {
  return timestamp;
 }
 public void setTimestamp(Date timestamp) {
  this.timestamp = timestamp;
 }
 public String getHostname() {
  return hostname;
 }
 public void setHostname(String hostname) {
  this.hostname = hostname;
 }
 public String getChannel() {
  return channel;
 }
 public void setChannel(String channel) {
  this.channel = channel;
 }
 
 // end of getters and setters
 
 public boolean isLoggedIn() {
  return loginType != null && !loginType.equals(LOGGED_OFF);
 }
 
 public String getAgentName() {
  if (id > 0) {
   try {
    Users user = new UsersDao().getById(id);
    if (user != null) {
     agentName = user.getLast() + ", " + user.getFirst();
     laborType = new LaborTypeDao().getById(user.getLaborTypeId());
    }
   }
   finally {
    HibernateUtil.closeCurremycompanyession();
   }
  }
  
  return agentName;
 }
 
 public String getHoldTimestamp() {
  String holdTime = null;
  
   long elapsedTime = Calendar.getInstance().getTimeInMillis() - getLastCall().getTime();
   long secondInMillis = 1000;
   long minuteInMillis = secondInMillis * 60;
   long hourInMillis = minuteInMillis * 60;
   long dayInMillis = hourInMillis * 24;
   
   elapsedTime %= dayInMillis;
   elapsedTime %= hourInMillis;
   
   long elapsedMinute = elapsedTime / minuteInMillis;
   elapsedTime %= minuteInMillis;
   
   long elapsedSecond = elapsedTime / secondInMillis;
   
   holdTime = String.format("%02d", elapsedMinute) + ":" + String.format("%02d", elapsedSecond);
  
  return holdTime;
 }
 
 public String getAgentIcon() {
  return null;
 }
 
 public String getTimestampAsHhmmss() {
  if (timestamp != null)
   return new SimpleDateFormat("HH:mm:ss").format(timestamp);
  else
   return "";
 }
}



package net.mycompany.asteriskmon;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.annotation.WebServlet;

import net.mycompany.asterisk.model.Channel;
import net.mycompany.asteriskmon.misc.TpsAmProperties;
import net.mycompany.asteriskmon.util.MonitorProperties;
import net.mycompany.tps.ami.util.AmiEventCatcher;
import net.mycompany.tps.blvd.domain.AgentStatus;

import org.apache.log4j.Logger;
import org.asteriskjava.manager.ManagerConnection;
import org.asteriskjava.manager.ManagerEventListener;
import org.asteriskjava.manager.event.HangupEvent;
import org.asteriskjava.manager.event.ManagerEvent;
import org.asteriskjava.manager.event.NewExtenEvent;
import org.asteriskjava.manager.event.VarSetEvent;

import com.vaadin.addon.jpacontainer.EntityItem;
import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.annotations.Push;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.Title;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Property;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItem;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinService;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.CheckBox;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.JavaScript;
import com.vaadin.ui.Table;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;

@SuppressWarnings("serial")
@Title("TPS2 Monitor")
@Push
@Theme("mytheme")
public class TpsMonitorUI extends UI implements ManagerEventListener {
 @WebServlet(value ={"/*"}, asyncSupported = true)
 @VaadinServletConfiguration(heartbeatInterval = 60, productionMode = false, ui = TpsMonitorUI.class)
 public static class Servlet extends VaadinServlet { }

 private transient static Logger logger = Logger.getLogger(TpsMonitorUI.class);
 BeanContainer<String, Channel> callers;
 BeanContainer<String, Channel> agents;
 BeanContainer<String, Summary> summaries;
 private Table callerTable, agentTable, summaryTable;
 private Map<String, Boolean> isWaitingForStatusEvemycompany = new HashMap<String,Boolean>();
 private int agentsOneOnOne = 0;
 private int callersOneOnOne = 0;
 private static String TEXT_FIELD_WIDTH="200";
 private Map<String,String> agentOnCallStateMap = new HashMap<String,String>();
 private Map<String,String> agentGroupOnCallStateMap = new HashMap<String,String>();
 private long lastUpdatedAgentStatus;
 private static JPAContainer<AgentStatus> agentstatus;
 private static List<AgentStatus> agentstatusList = new ArrayList<AgentStatus>(100);
 @Override
 protected void init(VaadinRequest request) {
  initCallerTable();
  initAgentTable();
  initSummaryTable();
  initLayout();
  initAmiEventCatcher();
  logger.info("Started UI: "+hashCode());
  // Read the JS File and Process it
  JavaScript.getCurrent().execute(readJsFile("refresh.js"));
  
  agentstatus = JPAContainerFactory.make(AgentStatus.class, "agent-status");
 }
 
 private void initCallerTable() {
  callers = new BeanContainer<String, Channel>(Channel.class);
  callers.setBeanIdProperty("name");
  callerTable = new Table("Callers", callers);
  callerTable.setImmediate(true);
        callerTable.setColumnHeader("timestampAsHhmmss", "Start");
        callerTable.setColumnHeader("hostname", "Host");
        callerTable.setVisibleColumns(new Object[] {"timestampAsHhmmss", "ani", "dnis", "product"}); 
        callerTable.setSelectable(true);
        callerTable.setPageLength(0); // to not have scrollbars
        
        callerTable.addItemClickListener(new MonitorItemClickListener());
    }

 private void initAgentTable() {
  agents = new BeanContainer<String, Channel>(Channel.class);
  agents.setBeanIdProperty("name");
  agentTable = new Table("AgentS", agents);
  agentTable.setImmediate(true);
  agentTable.setColumnHeader("agentIcon", "");
  agentTable.setColumnHeader("agentName", "Agent Name");
  agentTable.setColumnHeader("holdTimestamp", "Hold");
  agentTable.setColumnHeader("timestampAsHhmmss", "Start");
  agentTable.setColumnWidth("agentIcon", 60);
  agentTable.setColumnHeader("hostname", "Host");
  agentTable.setVisibleColumns(new Object[] {"agentIcon", "agentName", "holdTimestamp", "timestampAsHhmmss", "agent", "product", "hostname"});
  agentTable.setSelectable(true);
  agentTable.setPageLength(0); // to not have scrollbars
  agentTable.setSortContainerPropertyId("agentName");
  agentTable.setSortAscending(true);
  
  agentTable.addGeneratedColumn("agentIcon", new IconColumnGenerator("laborType", "type", "paused"));
        agentTable.addItemClickListener(new MonitorItemClickListener());
        agentTable.setCellStyleGenerator(new Table.CellStyleGenerator()  {
   @Override
   public String getStyle(Table source, Object itemId, Object propertyId) {
    String itemString;
    if (propertyId == null || itemId == null) return null;
    Property prop = source.getContainerProperty(itemId, propertyId);
    if (prop == null || prop.getValue() == null)
     return "agent-value";
    if (propertyId.equals("agent")) {
     String agentstate = getAgentState((String)prop.getValue(), (String)itemId);
     switch(agentstate) {
      case Channel.STATE_ON_CALL:
       return "agent-value stateOnCall";
      case Channel.STATE_IDLE:
       return "agent-value stateIdle";
      case Channel.STATE_SUPERVISOR:
       return "agent-value stateSupervisor";
     default:
      return "agent-value";
     }
    }
    
    return "agent-value";
   }
  });
        
        lastUpdatedAgentStatus = System.currentTimeMillis();
    }

 private void initSummaryTable() {
  summaries = new BeanContainer<String, Summary>(Summary.class);
  summaries.setBeanIdProperty("name");
  Summary summary = new Summary();
  summary.setName("summary");
  summaries.addBean(summary);
  summaryTable = new Table();
  summaryTable.setContainerDataSource(summaries);
  summaryTable.setImmediate(true);
  summaryTable.setColumnHeader("callersInStories", "Stories");
  summaryTable.setColumnHeader("callersInMessages", "Messages");
  summaryTable.setColumnHeader("callersInDirectory", "Directory");
  summaryTable.setColumnHeader("oneOnOne", "1on1");
  summaryTable.setVisibleColumns(new Object[] {"channels", "oneOnOne", "group", "callersInStories", "callersInMessages", "callersInDirectory"}); 
  summaryTable.setSelectable(true);
  summaryTable.setColumnWidth("channels", 100);
  summaryTable.setColumnWidth("oneOnOne", 150);
  summaryTable.setColumnWidth("group", 120);
  
        summaryTable.setCellStyleGenerator(new Table.CellStyleGenerator()  {
   @Override
   public String getStyle(Table source, Object itemId, Object propertyId) {
    String itemString;
    logger.debug(source+","+itemId+","+propertyId);

    if (propertyId == null || itemId == null) return null;
    Property prop = source.getContainerProperty(itemId, propertyId);

    if (propertyId.equals("channels")) {
     int itemInt = (int) prop.getValue();
     double usedChannelPercent = 0;
     try {
      usedChannelPercent = 100.0 * itemInt / MonitorProperties.maxChannels();
     } catch (Exception e) {
      logger.error("Failed to calculate used channels",e);
     }
     if (usedChannelPercent >= 85) return "summary-value red";
     if (usedChannelPercent >= 75) return "summary-value orange";
    }
    
    if (propertyId.equals("oneOnOne")) {
     if (agentsOneOnOne == 0 || callersOneOnOne == 0) return "summary-value red";
     double callerToAgentRatio = 100.0 * callersOneOnOne / agentsOneOnOne;
     if (callerToAgentRatio >= 85) return "summary-value red";
     if (callerToAgentRatio >= 75) return "summary-value orange";
    }

    if (propertyId.equals("group")) {
     itemString = (String) prop.getValue();
     if (itemString == null) return null;
     if (itemString.startsWith("0|")) return "summary-value red";
    }

    return "summary-value";
   }
  });

        summaryTable.setPageLength(1); // to not have scrollbars
 }
 
 private void initLayout() {
  VerticalLayout verticalLayout = new VerticalLayout();

  // Top of vertical layout
  verticalLayout.addComponent(summaryTable);

  // Bottom of vertical layout
  GridLayout channelsLayout = new GridLayout(2,1);
  channelsLayout.addComponent(callerTable,0,0);
  channelsLayout.addComponent(agentTable,1,0);
  verticalLayout.addComponent(channelsLayout);
  
   setContent(verticalLayout);
 }
 
 private void initAmiEventCatcher() {
  for(Map.Entry<String, ManagerConnection> me : AmiEventCatcher.amiManagerConnectionMap.entrySet()) {
   isWaitingForStatusEvemycompany.put(me.getKey(), true);
  }
  AmiEventCatcher.addEventListener(this);
  AmiEventCatcher.sendStatusAction();
 }
 
 @Override
 public void onManagerEvent(ManagerEvent event) {
  String hostName = ((ManagerConnection)event.getSource()).getHostname();
  String eventClassName = event.getClass().getSimpleName();
     switch (eventClassName) {
      case "DisconnectEvent":
       handleEvemycompanyafely(event);
       break;
      case "ConnectEvent":
       AmiEventCatcher.addEventListener(this);
       break;
      case "NewChannelEvent": // Create new channel objects
      case "HangupEvent":  // Remove channel objects
       handleEvemycompanyafely(event);
       updateSummaryTable();
       break;
      case "StatusEvent":  // Response to StatusAction
       if (isWaitingForStatusEvemycompany.get(hostName)) {
        handleEvemycompanyafely(event);
       }
       break;
      case "StatusCompleteEvent":
       isWaitingForStatusEvemycompany.put(hostName, false);
       updateSummaryTable();
       break;
   case "VarSetEvent":
          updateVar(event);
          updateSummaryTable();
          break;
   default:
    break;
  }
     
     // Needs method because vaadin will not update correctly if we create separate thread to update UI
     // Method is depended on AMI evemycompany
     // Works in production but updates might be delayed in dev
     try {
      handleAgentStatusUpdate();
     } catch (Exception e) {
      logger.error("cannot run handleagentstatusupdate", e);
     }
 }
 
 private void handleAgentStatusUpdate() throws Exception  {
  long elapsedTime = System.currentTimeMillis() - lastUpdatedAgentStatus;
  
  if (elapsedTime >= TpsAmProperties.agentstatusManagerPollRate()) {
   new refreshAgentS().run();
      access(new Runnable() {
       @Override
       public void run() {
     // Iterate all logged in AgentS
        BeanItem<Channel> beanItem;
        String agentId;
     for (AgentStatus as : agentstatusList) {
      beanItem = agents.getItem(as.getChannel());
      if (beanItem != null) {
       agentId = (String)beanItem.getItemProperty("agent").getValue();
       // Agent Id must match
       if ((agentId != null) && (agentId.equals(as.getId() + ""))) {
        beanItem.getItemProperty("agentstatus").setValue(as);
        beanItem.getItemProperty("agent").setValue(agentId); // Force screen to refresh
       }
      }
     }
       }
      });
      
   // Update last updated timestamp
   lastUpdatedAgentStatus = System.currentTimeMillis();
  }
 }
 
 private void handleEvemycompanyafely(final ManagerEvent event) {
  final String eventClassName = event.getClass().getSimpleName();
  
     access(new Runnable() {
      @Override
      public void run() {
          switch (eventClassName) {
       case "NewChannelEvent": // New call comes in
        addNewChannel(event);
        break;
       case "StatusEvent": // Response to status action
        addNewChannelForStatusEvent(event);
        break;
       case "HangupEvent": // Hangup on a channel
           removeChannel(event);
           break;
       case "DisconnectEvent":
        agentTable.removeAllItems();
           callerTable.removeAllItems();
           summaryTable.removeAllItems();
           break;
          }
      }
     });
 }
 
 private void updateVar(ManagerEvent event) {
  final VarSetEvent vse = (VarSetEvent)event;

  switch(vse.getVariable()) {
   case "ACTIVE":
    String value = vse.getValue();
    if (value != null && value.equals("Agent-Login")) {
     final BeanItem<Channel> channelBean = getChannelBean(callers, vse.getChannel());
     if (channelBean != null) {
      access(new Runnable() {
       @Override
             public void run() {
        // Move from callers to agents table
        callers.removeItem(vse.getChannel());
        Channel bean = channelBean.getBean();
        bean.setUserType(Channel.AGENT);
        addChannelToTable(agents, bean);
       }
      });
     } 
    }
    break;
   case "GLOBALID":
    updateVar(vse, "globalId", false);
    break;
   case "AGENT":
    // If agent value is null, we are disconnecting from an agent.
    // Get callerChannel and cache the agent id as callersLastAgent
    String agent=getAgentForCaller(vse.getValue(), vse.getChannel());
    updateVar(vse, "agent", false); // Set caller channel agent var
    updateAgentState(agent, vse.getValue(), vse.getChannel());
    agentTable.sort(); // Name is populated after agent id is set
    break;
   case "ANI":
    updateVar(vse, "ani", true);
    break;
   case "DNIS":
    updateVar(vse, "dnis", true);
    break;
   case "PRODUCT":
    String previousProduct=getProductForCaller(vse.getValue(), vse.getChannel());
    updateVar(vse, "product", true);
    if (previousProduct != null && previousProduct.endsWith("group")) // caller moved out of group
      updateGroupAgentS();
    break;
  }
 }
 
 private void updateSummaryTable() {
  access(new Runnable() {
   @Override
      public void run() {
    BeanItem<Summary> summaryBean = getSummaryBean("summary");
    if (summaryBean == null) {
     Summary summary = new Summary();
     summary.setName("summary");
     summaries.addBean(summary);
     summaryBean = getSummaryBean("summary");
    }
    Map<String,Integer> agentProductMap = new HashMap<String,Integer>();
    Map<String,Integer> callerProductMap = new HashMap<String,Integer>();
    for(int i=0; i < agents.size(); i++) {
     String product = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("product").getValue();
     agentProductMap.put(product, agentProductMap.get(product) == null ? 1 : 1 + agentProductMap.get(product));
    }
    for(int i=0; i < callers.size(); i++) {
     String product = (String)callers.getItem(callers.getIdByIndex(i)).getItemProperty("product").getValue();
     callerProductMap.put(product, callerProductMap.get(product) == null ? 1 : 1 + callerProductMap.get(product));
    }
    // Set only if changed
    int totalChannels = callers.getItemIds().size() + agents.getItemIds().size();
    if ((int)summaryBean.getItemProperty("channels").getValue() != totalChannels)
     summaryBean.getItemProperty("channels").setValue(totalChannels);
    
    agentsOneOnOne=agentProductMap.get("agent-login-1on1") == null ? 0 : agentProductMap.get("agent-login-1on1");
    callersOneOnOne=callerProductMap.get("1on1") == null ? 0 : callerProductMap.get("1on1");
    
    String oneOnOneStr = agentsOneOnOne + "|" + callersOneOnOne;
    
    if (!oneOnOneStr.equals(summaryBean.getItemProperty("oneOnOne").getValue()))
     summaryBean.getItemProperty("oneOnOne").setValue(oneOnOneStr);
    
    int agentsInGroup = agentProductMap.get("agent-login-group") == null ? 0 : agentProductMap.get("agent-login-group");
    int callersInGroup = callerProductMap.get("group") == null ? 0 : callerProductMap.get("group");
    
    String groupStr = agentsInGroup + "|" + callersInGroup;
    if (!groupStr.equals(summaryBean.getItemProperty("group").getValue()))
     summaryBean.getItemProperty("group").setValue(groupStr);
    
    int callersInStories = callerProductMap.get("stories") == null ? 0 : callerProductMap.get("stories");
    if (callersInStories != (int)summaryBean.getItemProperty("callersInStories").getValue())
     summaryBean.getItemProperty("callersInStories").setValue(callersInStories);
    
    int callersInMessages = callerProductMap.get("messages") == null ? 0 : callerProductMap.get("messages");
    if (callersInMessages != (int)summaryBean.getItemProperty("callersInMessages").getValue())
     summaryBean.getItemProperty("callersInMessages").setValue(callersInMessages);
    
    int callersInDirectory = callerProductMap.get("directory") == null ? 0 : callerProductMap.get("directory");
    if (callersInDirectory != (int)summaryBean.getItemProperty("callersInDirectory").getValue())
     summaryBean.getItemProperty("callersInDirectory").setValue(callersInDirectory);
   };
  });
 }
 
 private void updateVar(final VarSetEvent vse, final String beanVarName, boolean shouldUpdateScreen) {
  
  final BeanItem<Channel> channelBean = getChannelBean(vse.getChannel());
  if (channelBean != null)  {// Make sure we have it
   if (shouldUpdateScreen)
          access(new Runnable() {
           @Override
           public void run() {
            channelBean.getItemProperty(beanVarName).setValue(vse.getValue());
           }
       });
   else
    channelBean.getItemProperty(beanVarName).setValue(vse.getValue());
   
  }
  
 }
 
 private void updateNewExten(ManagerEvent event) {
  // Update caller context
  final NewExtenEvent nee = (NewExtenEvent) event;
  final BeanItem<Channel> channelBean = getChannelBean(nee.getChannel());
     if (channelBean == null) return; // Make sure we have it
     
     String currentValue = channelBean.getBean().getContext();
     String newValue = nee.getContext();
     if (!currentValue.equals(newValue)) { 
         access(new Runnable() {
          @Override
          public void run() {
           channelBean.getItemProperty("context").setValue(nee.getContext());
          }
      });
     }
 }
 
 private void removeChannel(ManagerEvent event) {
  HangupEvent he = (HangupEvent) event;
     if (!callers.removeItem(he.getChannel())) 
      agents.removeItem(he.getChannel());
 }
 
 private void addNewChannel(ManagerEvent event) {
  Channel newChannel = new Channel(event);
  if (!isValidChannel(newChannel) || newChannel.isFromTpsPeer()) 
   return;
  
  Object returnId = addChannelToTable(callers, newChannel);
     if (returnId == null) logger.error("Failed during "+event);
 }
 
 private void addNewChannelForStatusEvent(ManagerEvent event) { // this method called upon browser refresh
  
  Channel newChannel = new Channel(event);
  if (!isValidChannel(newChannel) || newChannel.isFromTpsPeer() || newChannel.getDnis() == null || newChannel.getDnis().trim().equals("")) 
   return;
  
  String hostName  = ((ManagerConnection)event.getSource()).getHostname();
  String active=AmiEventCatcher.getChannelVariable(newChannel.getName(), "ACTIVE", hostName);
  Object returnId=null;
  String product = newChannel.getProduct();
  String agent = newChannel.getAgent();
  if (active != null && active.equals("Agent-Login")) {
   newChannel.setUserType(Channel.AGENT);
   returnId = addChannelToTable(agents, newChannel);
   if (agentOnCallStateMap.get(agent) != null) {
    if (product.endsWith("supervisor") || product.endsWith("monitor"))
     setAgentState(agent, Channel.STATE_SUPERVISOR);
    else
     setAgentState(agent, Channel.STATE_ON_CALL);
   } else if (newChannel.getState().equals(Channel.STATE_NOT_LOGGED_IN)) {// only set idle on a not logged in default state
    if (product.endsWith("group"))
     setAgentState(agent, Channel.STATE_IDLE);
    else if (product.endsWith("supervisor") || product.endsWith("monitor"))
     setAgentState(agent, Channel.STATE_SUPERVISOR);
    else
     setAgentState(agent, Channel.STATE_IDLE);
   }
   if (agentGroupOnCallStateMap.get("0") != null) { // group agents have zero for agent id
    markStateOfGroupAgentS(Channel.STATE_ON_CALL);
   }
  } else {
   returnId = addChannelToTable(callers, newChannel);
   if (agent != null) {
    if (product.endsWith("group")) {
     agentGroupOnCallStateMap.put(agent, Channel.STATE_ON_CALL); // we got caller event before the agent event 
     markStateOfGroupAgentS(Channel.STATE_ON_CALL);
    } else {
     agentOnCallStateMap.put(agent, Channel.STATE_ON_CALL); // we got caller event before the agent event 
     setAgentState(agent, Channel.STATE_ON_CALL);
    }
   }
  }
     if (returnId == null) {
      logger.error("Adding to table returned null. event: "+event);
     }
 }
 
 private BeanItem<Channel> getChannelBean(BeanContainer<String, Channel> beanContainer, String channel) {
  BeanItem<Channel> channelBean = beanContainer.getItem(channel);
     return channelBean;
 }
 
 private BeanItem<Channel> getChannelBean(String channel) {
  BeanItem<Channel> channelBean = callers.getItem(channel);
  if ( channelBean == null) 
      return agents.getItem(channel);
  else 
   return channelBean;
 }
 private BeanItem<Summary> getSummaryBean(String name) {
  return summaries.getItem(name);
 }
 @Override
 public void detach() {
  super.detach();
  AmiEventCatcher.removeEventListener(this);
  
  if (logger != null) logger.info("Detached UI: "+hashCode());
 }
 
 private Object addChannelToTable(BeanContainer<String, Channel> beanContainer, Channel newChannel) {
  Object returnId = beanContainer.addBean(newChannel);
  return returnId;
 }
 
 private boolean isValidChannel(Channel newChannel) {
  // Check for DAHDI channel
  if (newChannel.isStateReserved()) return false;
  
  // Filter for whisper tags
  if (newChannel.getName().contains("whispertag")) return false;
  //if (newChannel.getAni() == null && newChannel.getDnis() == null) return false;
  
  try {
   // filter Canadian redirect after the FTC is denied access by the operator
   if (newChannel.getName().contains(MonitorProperties.canadianRedirectIp()))
    return false;
  } catch (Exception e) {
   logger.error("Canadian Redirect IP not set", e);
  }
  return true;
 }
 
 private String readJsFile(String jsFile) {
  String basepath = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
  BufferedReader br=null;
  StringBuffer javaScript= new StringBuffer();
  try {
   br= new BufferedReader(new FileReader(new File(basepath + "/" + jsFile)));
   String line="";
   while((line=br.readLine()) != null) {
    javaScript.append(line);
   }
  } catch (Exception e) {
   logger.error("can't read js file", e);
  } finally {
   try {
    br.close();
   } catch (Exception e) {}
  }
  String refreshInterval=null;
  try {
   refreshInterval = MonitorProperties.refreshSeconds();
  } catch (Exception e) {
   logger.warn("refresh interval not set in properties", e);
   refreshInterval = "30";
  }
  return javaScript.toString().
    replaceAll("refreshInterval", refreshInterval);
 }
 
 private FormLayout getChannelInfoLayout(Channel channelBean) {
  
  FormLayout formLayout = new FormLayout();
  
  TextField textField = new TextField("Channel Name");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getName());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  textField = new TextField("Agent");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getAgent());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  if (channelBean.getUserType() != null && channelBean.getUserType().equals(Channel.AGENT)) {
   textField = new TextField("Agent Name");
   textField.setWidth(TEXT_FIELD_WIDTH);
   textField.setValue(channelBean.getAgentName());
   textField.setReadOnly(true);
   formLayout.addComponent(textField);
   
   textField = new TextField("Type");
   textField.setWidth(TEXT_FIELD_WIDTH);
   textField.setValue(channelBean.getType());
   textField.setReadOnly(true);
   formLayout.addComponent(textField);
   
   textField = new TextField("Labor Type");
   textField.setWidth(TEXT_FIELD_WIDTH);
   textField.setValue(channelBean.getLaborType());
   textField.setReadOnly(true);
   formLayout.addComponent(textField);
   
   textField = new TextField("State");
   textField.setWidth(TEXT_FIELD_WIDTH);
   String agentstate=getAgentState(channelBean.getAgent(), channelBean.getName());
   textField.setValue(agentstate);
   textField.setReadOnly(true);
   formLayout.addComponent(textField);
   
   textField = new TextField("Last Call");
   textField.setWidth(TEXT_FIELD_WIDTH);
   textField.setValue(channelBean.getAgentStatus().getLastCall().toString());
   textField.setReadOnly(true);
   formLayout.addComponent(textField);
  }
  
  textField = new TextField("Start");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getTimestamp() == null ? "" : channelBean.getTimestamp().toString());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  textField = new TextField("Global ID");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getGlobalId());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  textField = new TextField("ANI");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getAni());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  textField = new TextField("DNIS");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getDnis());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  textField = new TextField("Product");
  textField.setWidth(TEXT_FIELD_WIDTH);
  textField.setValue(channelBean.getProduct());
  textField.setReadOnly(true);
  formLayout.addComponent(textField);
  
  if (channelBean.getProduct().equals("agent-login-1on1")) {
   CheckBox checkbox = new CheckBox("Pause");
   checkbox.setWidth(TEXT_FIELD_WIDTH);
   checkbox.setValue(channelBean.getAgentPaused());
   checkbox.setImmediate(true);
   checkbox.addListener(new PauseClickListener(channelBean));
   formLayout.addComponent(checkbox);
  }
  
  formLayout.setMargin(true);
  return formLayout;
 }
 
 private void showChannelPopup(String channel) {
  BeanItem<Channel> beanItem = getChannelBean(channel);
  if (beanItem == null)
   return;
  Channel channelBean = beanItem.getBean();
  FormLayout formLayout = getChannelInfoLayout(channelBean);
  if (formLayout != null) {
   Window channelPop = new Window("Channel Info for " + channelBean.getUserType());
   channelPop.setModal(false);
   channelPop.setClosable(true);
   channelPop.setResizable(false);
   channelPop.setDraggable(true);
   channelPop.setContent(formLayout);
   addWindow(channelPop);
  }
 }
 
 class MonitorItemClickListener implements ItemClickListener {
  public void itemClick(ItemClickEvent event) {
         logger.info("event:" + event);
         if (event.isDoubleClick()) {
          String val = event.getItemId().toString();
          if (val != null && !val.trim().equals("")) {
                 showChannelPopup(val);
          }
         }
  }
 }
 
 private String getAgentState(String agent, String channelName) {
  BeanItem<Channel> channelBean = getAgentChannelBeanItemForChannel(agent, channelName);
  return channelBean == null ? Channel.STATE_NOT_LOGGED_IN : channelBean.getBean().getState();
 }
 
 private BeanItem<Channel> getAgentChannelBeanItemForChannel(String agent, String channelName) {
  for(int i=0; i < agents.size(); i++) {
   String agentId = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("agent").getValue();
   String agentChannel = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("name").getValue();
   if (agentId != null && agentId.equals(agent) && agentChannel != null && agentChannel.equals(channelName)) {
    return agents.getItem(agents.getIdByIndex(i));
   }
  }
  return null;
 }
 
 private BeanItem<Channel> getAgentChannelBeanItemForProduct(String agent, String product) {
  for(int i=0; i < agents.size(); i++) {
   String agentId = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("agent").getValue();
   String agentProduct = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("product").getValue();
   if (agentId != null && agentId.equals(agent) && agentProduct != null && agentProduct.endsWith(product)) {
    return agents.getItem(agents.getIdByIndex(i));
   }
  }
  return null;
 }
 
 private boolean isCallersInGroup() {
  for(int i=0; i < callers.size(); i++) {
   String product = (String)callers.getItem(callers.getIdByIndex(i)).getItemProperty("product").getValue();
   if (product != null && product.endsWith("group")) {
    return true;
   }
  }
  return false;
 }
 
 private void setAgentState(final String agent, final String state) {
  BeanItem<Channel> beanItem=null;
  switch(state) {
   case Channel.STATE_SUPERVISOR:
    // assume supervisor has two products supervisor and monitor
    beanItem = getAgentChannelBeanItemForProduct(agent, "supervisor");
    if (beanItem == null)
     beanItem = getAgentChannelBeanItemForProduct(agent, "monitor");
    break;
   default:
    // assume an agent can only have 2 products: 1on1 and group
    beanItem = getAgentChannelBeanItemForProduct(agent, "1on1");
    if (beanItem == null)
     beanItem = getAgentChannelBeanItemForProduct(agent, "group");
  }
  final BeanItem<Channel>channelBean = beanItem;
  if (channelBean == null)
   return;
  access(new Runnable() {
      @Override
      public void run() {
        channelBean.getItemProperty("state").setValue(state);
        channelBean.getItemProperty("agent").setValue(agent);
      }
  });
  
 }
 
 private String getAgentForCaller(String eventVal, String eventChannel) {
  if (eventVal == null) {
   BeanItem<Channel> channelBeanItem = getChannelBean(callers, eventChannel);
   if (channelBeanItem != null) {
    Channel callerChannel = channelBeanItem.getBean();
    return callerChannel.getAgent(); // cache the agent id returned from here
   } 
  } 
  return null;
 }
 
 private void updateAgentState(String agent, String eventVal, String eventChannel) {
  if (eventChannel.contains("whispertag")) 
   return;
  if (agent != null) { // cached agent id is available 
   // caller disconnected from agent
   setAgentState(agent, Channel.STATE_IDLE);
   updateGroupAgentS();
  } else {
   // we don't have a cached agent id, use the eventVal for agent
   BeanItem<Channel> channelBeanItem = getChannelBean(callers, eventChannel);
   if (channelBeanItem != null) { 
    // the event came through caller's channel
    // the caller is associated with the agent in eventVal
    String product = channelBeanItem.getBean().getProduct();
    if (product != null && product.contains("group")) {
     markStateOfGroupAgentS(Channel.STATE_ON_CALL);
    } else {
     setAgentState(eventVal, Channel.STATE_ON_CALL);
    }
   } else {
    // the event came through agent's channel
    // agent login triggered the event
    channelBeanItem = getChannelBean(agents, eventChannel);
    if (channelBeanItem == null)
     return;
    Object product=channelBeanItem.getItemProperty("product").getValue();
    if (product == null)
     return;
    if (product.toString().endsWith("group"))
     updateGroupAgentS();
    else if (product.toString().endsWith("supervisor") || product.toString().endsWith("monitor"))
     setAgentState(eventVal, Channel.STATE_SUPERVISOR);
    else if (!product.equals("idle")) //supervisor has this product idle
     setAgentState(eventVal, Channel.STATE_IDLE);
   }
  }
 }
 private void markStateOfGroupAgentS(String state) {
  //mark all beans with group as product to be on-call
  for(int i=0; i < agents.size(); i++) {
   String agentId = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("agent").getValue();
   String agentProduct = (String)agents.getItem(agents.getIdByIndex(i)).getItemProperty("product").getValue();
   if (agentProduct.endsWith("group")) {
    setAgentState(agentId, state);
   }
  }
 }
 
 private void updateGroupAgentS() {
  if (!isCallersInGroup()) { // do we have any callers in the group?
   // mark all group agents as IDLE
   markStateOfGroupAgentS(Channel.STATE_IDLE);
  } else {
   // mark all group agents as ONCALL
   markStateOfGroupAgentS(Channel.STATE_ON_CALL);
  }
 }
 
 private String getProductForCaller(String eventVal, String eventChannel) {
  BeanItem<Channel> channelBeanItem = getChannelBean(callers, eventChannel);
  if (channelBeanItem != null) {
   Channel callerChannel = channelBeanItem.getBean();
   return callerChannel.getProduct(); // cache the product returned from here
  } 
  return null;
 }
 
 static class refreshAgentS {
  public void run() {
   agentstatus.refresh();
   agentstatusList.clear();
   for(int i=0; i < agentstatus.size(); i++) {
     int iid = (Integer)agentstatus.getIdByIndex(i);
     EntityItem<AgentStatus> item = agentstatus.getItem(iid);
     AgentStatus agentstatus = (AgentStatus)item.getEntity();
     if (agentstatus != null && agentstatus.getLoginType().equals(AgentStatus.LOGGED_OFF)) {
      continue;
     }
     agentstatusList.add(agentstatus);
    }
   logger.info("In Refresh AgentS; size: " + agentstatusList.size() + " agentstatus size: " + agentstatus.size());
  }
 }
}

No comments:

Post a Comment