mirror of https://github.com/sipwise/jitsi.git
parent
90e516e1bb
commit
19ad943a80
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.callhistory;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.history.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
import net.java.sip.communicator.service.callhistory.*;
|
||||
|
||||
/**
|
||||
* Activates the CallHistoryService
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class CallHistoryActivator
|
||||
implements BundleActivator
|
||||
{
|
||||
private static Logger logger =
|
||||
Logger.getLogger(CallHistoryActivator.class);
|
||||
|
||||
private CallHistoryServiceImpl callHistoryService = null;
|
||||
|
||||
/**
|
||||
* Initialize and start call history
|
||||
*
|
||||
* @param bundleContext BundleContext
|
||||
* @throws Exception
|
||||
*/
|
||||
public void start(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
try{
|
||||
|
||||
logger.logEntry();
|
||||
|
||||
ServiceReference refHistory = bundleContext.getServiceReference(
|
||||
HistoryService.class.getName());
|
||||
|
||||
HistoryService historyService = (HistoryService)
|
||||
bundleContext.getService(refHistory);
|
||||
|
||||
//Create and start the call history service.
|
||||
callHistoryService =
|
||||
new CallHistoryServiceImpl();
|
||||
// set the configuration and history service
|
||||
callHistoryService.setHistoryService(historyService);
|
||||
|
||||
callHistoryService.start(bundleContext);
|
||||
|
||||
bundleContext.registerService(
|
||||
CallHistoryService.class.getName(), callHistoryService, null);
|
||||
|
||||
logger.info("Call History Service ...[REGISTERED]");
|
||||
}
|
||||
finally
|
||||
{
|
||||
logger.logExit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void stop(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,900 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.callhistory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import net.java.sip.communicator.service.callhistory.*;
|
||||
import net.java.sip.communicator.service.callhistory.event.*;
|
||||
import net.java.sip.communicator.service.contactlist.*;
|
||||
import net.java.sip.communicator.service.history.*;
|
||||
import net.java.sip.communicator.service.history.event.*;
|
||||
import net.java.sip.communicator.service.history.event.ProgressEvent;
|
||||
import net.java.sip.communicator.service.history.records.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* The Call History Service stores info about the calls made.
|
||||
* Logs calls info for all protocol providers that support basic telephony
|
||||
* (i.e. those that implement OperationSetBasicTelephony).
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class CallHistoryServiceImpl
|
||||
implements CallHistoryService,
|
||||
CallListener,
|
||||
ServiceListener
|
||||
{
|
||||
/**
|
||||
* The logger for this class.
|
||||
*/
|
||||
private static Logger logger = Logger
|
||||
.getLogger(CallHistoryServiceImpl.class);
|
||||
|
||||
private static String[] STRUCTURE_NAMES =
|
||||
new String[] { "callStart", "callEnd", "dir", "callParticipantIDs",
|
||||
"callParticipantStart", "callParticipantEnd" };
|
||||
|
||||
private static HistoryRecordStructure recordStructure =
|
||||
new HistoryRecordStructure(STRUCTURE_NAMES);
|
||||
|
||||
private static final String DELIM = ",";
|
||||
|
||||
/**
|
||||
* The BundleContext that we got from the OSGI bus.
|
||||
*/
|
||||
private BundleContext bundleContext = null;
|
||||
|
||||
private HistoryService historyService = null;
|
||||
|
||||
private Object syncRoot_HistoryService = new Object();
|
||||
|
||||
private Hashtable progressListeners = new Hashtable();
|
||||
|
||||
private Vector currentCallRecords = new Vector();
|
||||
|
||||
private HistoryCallChangeListener historyCallChangeListener
|
||||
= new HistoryCallChangeListener();
|
||||
|
||||
public HistoryService getHistoryService()
|
||||
{
|
||||
return historyService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made by all the contacts
|
||||
* in the supplied metacontact after the given date
|
||||
*
|
||||
* @param contact MetaContact
|
||||
* @param startDate Date the start date of the calls
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByStartDate(MetaContact contact, Date startDate)
|
||||
throws RuntimeException
|
||||
{
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made after the given date
|
||||
*
|
||||
* @param startDate Date the start date of the calls
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByStartDate(Date startDate) throws RuntimeException
|
||||
{
|
||||
TreeSet result = new TreeSet(new CallRecordComparator());
|
||||
try
|
||||
{
|
||||
// the default ones
|
||||
History history = this.getHistory(null, null);
|
||||
HistoryReader reader = history.getReader();
|
||||
addHistorySearchProgressListeners(reader, 1);
|
||||
QueryResultSet rs = reader.findByStartDate(startDate);
|
||||
while (rs.hasNext())
|
||||
{
|
||||
HistoryRecord hr = (HistoryRecord) rs.next();
|
||||
result.add(convertHistoryRecordToCallRecord(hr));
|
||||
}
|
||||
removeHistorySearchProgressListeners(reader);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("Could not read history", ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made by all the contacts
|
||||
* in the supplied metacontact before the given date
|
||||
*
|
||||
* @param contact MetaContact
|
||||
* @param endDate Date the end date of the calls
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByEndDate(MetaContact contact, Date endDate)
|
||||
throws RuntimeException
|
||||
{
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made before the given date
|
||||
*
|
||||
* @param endDate Date the end date of the calls
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByEndDate(Date endDate) throws RuntimeException
|
||||
{
|
||||
TreeSet result = new TreeSet(new CallRecordComparator());
|
||||
try
|
||||
{
|
||||
// the default ones
|
||||
History history = this.getHistory(null, null);
|
||||
HistoryReader reader = history.getReader();
|
||||
addHistorySearchProgressListeners(reader, 1);
|
||||
QueryResultSet rs = reader.findByEndDate(endDate);
|
||||
while (rs.hasNext())
|
||||
{
|
||||
HistoryRecord hr = (HistoryRecord) rs.next();
|
||||
result.add(convertHistoryRecordToCallRecord(hr));
|
||||
}
|
||||
removeHistorySearchProgressListeners(reader);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("Could not read history", ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made by all the contacts
|
||||
* in the supplied metacontact between the given dates
|
||||
*
|
||||
* @param contact MetaContact
|
||||
* @param startDate Date the start date of the calls
|
||||
* @param endDate Date the end date of the conversations
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByPeriod(MetaContact contact, Date startDate, Date endDate)
|
||||
throws RuntimeException
|
||||
{
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the calls made between the given dates
|
||||
*
|
||||
* @param startDate Date the start date of the calls
|
||||
* @param endDate Date the end date of the conversations
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findByPeriod(Date startDate, Date endDate) throws
|
||||
RuntimeException
|
||||
{
|
||||
TreeSet result = new TreeSet(new CallRecordComparator());
|
||||
try
|
||||
{
|
||||
// the default ones
|
||||
History history = this.getHistory(null, null);
|
||||
HistoryReader reader = history.getReader();
|
||||
addHistorySearchProgressListeners(reader, 1);
|
||||
QueryResultSet rs = reader.findByPeriod(startDate, endDate);
|
||||
while (rs.hasNext())
|
||||
{
|
||||
HistoryRecord hr = (HistoryRecord) rs.next();
|
||||
result.add(convertHistoryRecordToCallRecord(hr));
|
||||
}
|
||||
removeHistorySearchProgressListeners(reader);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("Could not read history", ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supplied number of calls by all the contacts
|
||||
* in the supplied metacontact
|
||||
*
|
||||
* @param contact MetaContact
|
||||
* @param count calls count
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findLast(MetaContact contact, int count)
|
||||
throws RuntimeException
|
||||
{
|
||||
throw new UnsupportedOperationException("Not implemented yet!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supplied number of calls made
|
||||
*
|
||||
* @param count calls count
|
||||
* @return Collection of CallRecords with CallParticipantRecord
|
||||
* @throws RuntimeException
|
||||
*/
|
||||
public Collection findLast(int count) throws RuntimeException
|
||||
{
|
||||
TreeSet result = new TreeSet(new CallRecordComparator());
|
||||
try
|
||||
{
|
||||
// the default ones
|
||||
History history = this.getHistory(null, null);
|
||||
QueryResultSet rs = history.getReader().findLast(count);
|
||||
while (rs.hasNext())
|
||||
{
|
||||
HistoryRecord hr = (HistoryRecord) rs.next();
|
||||
result.add(convertHistoryRecordToCallRecord(hr));
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("Could not read history", ex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the history by specified local and remote contact
|
||||
* if one of them is null the default is used
|
||||
*
|
||||
* @param localContact Contact
|
||||
* @param remoteContact Contact
|
||||
* @return History
|
||||
* @throws IOException
|
||||
*/
|
||||
private History getHistory(Contact localContact, Contact remoteContact)
|
||||
throws IOException {
|
||||
History retVal = null;
|
||||
|
||||
String localId = localContact == null ? "default" : localContact
|
||||
.getAddress();
|
||||
String remoteId = remoteContact == null ? "default" : remoteContact
|
||||
.getAddress();
|
||||
|
||||
HistoryID historyId = HistoryID.createFromID(new String[] { "callhistory",
|
||||
localId, remoteId });
|
||||
|
||||
if (this.historyService.isHistoryExisting(historyId))
|
||||
{
|
||||
retVal = this.historyService.getHistory(historyId);
|
||||
} else {
|
||||
retVal = this.historyService.createHistory(historyId,
|
||||
recordStructure);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to convert HistoryRecord in CallReord and CallParticipantRecord
|
||||
* which are returned by the finder methods
|
||||
*
|
||||
* @param hr HistoryRecord
|
||||
* @return Object CallRecord
|
||||
*/
|
||||
private Object convertHistoryRecordToCallRecord(HistoryRecord hr)
|
||||
{
|
||||
CallRecord result = new CallRecord();
|
||||
|
||||
LinkedList callParticipantIDs = null;
|
||||
LinkedList callParticipantStart = null;
|
||||
LinkedList callParticipantEnd = null;
|
||||
|
||||
// History structure
|
||||
// 0 - callStart
|
||||
// 1 - callEnd
|
||||
// 2 - dir
|
||||
// 3 - callParticipantIDs
|
||||
// 4 - callParticipantStart
|
||||
// 5 - callParticipantEnd
|
||||
|
||||
for (int i = 0; i < hr.getPropertyNames().length; i++)
|
||||
{
|
||||
String propName = hr.getPropertyNames()[i];
|
||||
String value = hr.getPropertyValues()[i];
|
||||
|
||||
if(propName.equals(STRUCTURE_NAMES[0]))
|
||||
result.setStartTime(new Date(Long.parseLong(value)));
|
||||
else if(propName.equals(STRUCTURE_NAMES[1]))
|
||||
result.setEndTime(new Date(Long.parseLong(value)));
|
||||
else if(propName.equals(STRUCTURE_NAMES[2]))
|
||||
result.setDirection(value);
|
||||
else if(propName.equals(STRUCTURE_NAMES[3]))
|
||||
callParticipantIDs = getCSVs(value);
|
||||
else if(propName.equals(STRUCTURE_NAMES[4]))
|
||||
callParticipantStart = getCSVs(value);
|
||||
else if(propName.equals(STRUCTURE_NAMES[5]))
|
||||
callParticipantEnd = getCSVs(value);
|
||||
}
|
||||
|
||||
for (int i = 0; i < callParticipantIDs.size(); i++)
|
||||
{
|
||||
|
||||
CallParticipantRecord cpr = new CallParticipantRecord(
|
||||
(String)callParticipantIDs.get(i),
|
||||
new Date(Long.parseLong((String)callParticipantStart.get(i))),
|
||||
new Date(Long.parseLong((String)callParticipantEnd.get(i)))
|
||||
);
|
||||
result.getParticipantRecords().add(cpr);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of String items contained in the supplied string
|
||||
* separated by DELIM
|
||||
* @param str String
|
||||
* @return LinkedList
|
||||
*/
|
||||
private LinkedList getCSVs(String str)
|
||||
{
|
||||
LinkedList result = new LinkedList();
|
||||
StringTokenizer toks = new StringTokenizer(str, DELIM);
|
||||
while(toks.hasMoreTokens())
|
||||
{
|
||||
result.add(toks.nextToken());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* starts the service. Check the current registerd protocol providers
|
||||
* which supports BasicTelephony and adds calls listener to them
|
||||
*
|
||||
* @param bc BundleContext
|
||||
*/
|
||||
public void start(BundleContext bc)
|
||||
{
|
||||
logger.debug("Starting the call history implementation.");
|
||||
this.bundleContext = bc;
|
||||
|
||||
// start listening for newly register or removed protocol providers
|
||||
bc.addServiceListener(this);
|
||||
|
||||
ServiceReference[] protocolProviderRefs = null;
|
||||
try
|
||||
{
|
||||
protocolProviderRefs = bc.getServiceReferences(
|
||||
ProtocolProviderService.class.getName(),
|
||||
null);
|
||||
}
|
||||
catch (InvalidSyntaxException ex)
|
||||
{
|
||||
// this shouldn't happen since we're providing no parameter string
|
||||
// but let's log just in case.
|
||||
logger.error(
|
||||
"Error while retrieving service refs", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
// in case we found any
|
||||
if (protocolProviderRefs != null)
|
||||
{
|
||||
logger.debug("Found "
|
||||
+ protocolProviderRefs.length
|
||||
+ " already installed providers.");
|
||||
for (int i = 0; i < protocolProviderRefs.length; i++)
|
||||
{
|
||||
ProtocolProviderService provider = (ProtocolProviderService) bc
|
||||
.getService(protocolProviderRefs[i]);
|
||||
|
||||
this.handleProviderAdded(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given record to the history service
|
||||
* @param callRecord CallRecord
|
||||
* @param source Contact
|
||||
* @param destination Contact
|
||||
*/
|
||||
private void writeCall(CallRecord callRecord, Contact source,
|
||||
Contact destination)
|
||||
{
|
||||
try {
|
||||
History history = this.getHistory(source, destination);
|
||||
HistoryWriter historyWriter = history.getWriter();
|
||||
|
||||
StringBuffer callParticipantIDs = new StringBuffer();
|
||||
StringBuffer callParticipantStartTime = new StringBuffer();
|
||||
StringBuffer callParticipantEndTime = new StringBuffer();
|
||||
|
||||
Iterator iter = callRecord.getParticipantRecords().iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
if(callParticipantIDs.length() > 0)
|
||||
{
|
||||
callParticipantIDs.append(DELIM);
|
||||
callParticipantStartTime.append(DELIM);
|
||||
callParticipantEndTime.append(DELIM);
|
||||
}
|
||||
|
||||
CallParticipantRecord item = (CallParticipantRecord) iter.next();
|
||||
callParticipantIDs.append(item.getParticipantAddress());
|
||||
callParticipantStartTime.append(String.valueOf(item.getStartTime().getTime()));
|
||||
callParticipantEndTime.append(String.valueOf(item.getEndTime().getTime()));
|
||||
}
|
||||
|
||||
historyWriter.addRecord(new String[] {
|
||||
String.valueOf(callRecord.getStartTime().getTime()),
|
||||
String.valueOf(callRecord.getEndTime().getTime()),
|
||||
callRecord.getDirection(),
|
||||
callParticipantIDs.toString(),
|
||||
callParticipantStartTime.toString(),
|
||||
callParticipantEndTime.toString()},
|
||||
new Date()); // this date is when the history record is written
|
||||
} catch (IOException e)
|
||||
{
|
||||
logger.error("Could not add call to history", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the configuration service.
|
||||
*
|
||||
* @param historyService HistoryService
|
||||
* @throws IOException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public void setHistoryService(HistoryService historyService)
|
||||
throws IllegalArgumentException, IOException {
|
||||
synchronized (this.syncRoot_HistoryService)
|
||||
{
|
||||
this.historyService = historyService;
|
||||
|
||||
logger.debug("New history service registered.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a configuration service.
|
||||
*
|
||||
* @param historyService HistoryService
|
||||
*/
|
||||
public void unsetHistoryService(HistoryService historyService)
|
||||
{
|
||||
synchronized (this.syncRoot_HistoryService)
|
||||
{
|
||||
if (this.historyService == historyService)
|
||||
{
|
||||
this.historyService = null;
|
||||
|
||||
logger.debug("History service unregistered.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When new protocol provider is registered we check
|
||||
* does it supports BasicTelephony and if so add a listener to it
|
||||
*
|
||||
* @param serviceEvent ServiceEvent
|
||||
*/
|
||||
public void serviceChanged(ServiceEvent serviceEvent)
|
||||
{
|
||||
Object sService = bundleContext.getService(serviceEvent.getServiceReference());
|
||||
|
||||
logger.trace("Received a service event for: " + sService.getClass().getName());
|
||||
|
||||
// we don't care if the source service is not a protocol provider
|
||||
if (! (sService instanceof ProtocolProviderService))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug("Service is a protocol provider.");
|
||||
if (serviceEvent.getType() == ServiceEvent.REGISTERED)
|
||||
{
|
||||
logger.debug("Handling registration of a new Protocol Provider.");
|
||||
|
||||
this.handleProviderAdded((ProtocolProviderService)sService);
|
||||
}
|
||||
else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING)
|
||||
{
|
||||
this.handleProviderRemoved( (ProtocolProviderService) sService);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to attach the Call History Service to existing or
|
||||
* just registered protocol provider. Checks if the provider has implementation
|
||||
* of OperationSetBasicTelephony
|
||||
*
|
||||
* @param provider ProtocolProviderService
|
||||
*/
|
||||
private void handleProviderAdded(ProtocolProviderService provider)
|
||||
{
|
||||
logger.debug("Adding protocol provider " + provider.getProtocolName());
|
||||
|
||||
// check whether the provider has a basic telephony operation set
|
||||
OperationSetBasicTelephony opSetTelephony
|
||||
= (OperationSetBasicTelephony) provider
|
||||
.getSupportedOperationSets().get(
|
||||
OperationSetBasicTelephony.class.getName());
|
||||
|
||||
if (opSetTelephony != null)
|
||||
{
|
||||
opSetTelephony.addCallListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.trace("Service did not have a basic telephony op. set.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified provider from the list of currently known providers
|
||||
* and ignores all the calls made by it
|
||||
*
|
||||
* @param provider the ProtocolProviderService that has been unregistered.
|
||||
*/
|
||||
private void handleProviderRemoved(ProtocolProviderService provider)
|
||||
{
|
||||
OperationSetBasicTelephony opSetTelephony
|
||||
= (OperationSetBasicTelephony) provider
|
||||
.getSupportedOperationSets().get(
|
||||
OperationSetBasicTelephony.class.getName());
|
||||
|
||||
if (opSetTelephony != null)
|
||||
{
|
||||
opSetTelephony.removeCallListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding progress listener for monitoring progress of search process
|
||||
*
|
||||
* @param listener HistorySearchProgressListener
|
||||
*/
|
||||
public void addSearchProgressListener(CallHistorySearchProgressListener
|
||||
listener)
|
||||
{
|
||||
synchronized(progressListeners){
|
||||
HistorySearchProgressListener wrapperListener =
|
||||
new SearchProgressWrapper(listener);
|
||||
progressListeners.put(listener, wrapperListener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removing progress listener
|
||||
*
|
||||
* @param listener HistorySearchProgressListener
|
||||
*/
|
||||
public void removeSearchProgressListener(
|
||||
CallHistorySearchProgressListener listener)
|
||||
{
|
||||
synchronized(progressListeners){
|
||||
progressListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the registered CallHistorySearchProgressListeners
|
||||
* to the given HistoryReader
|
||||
*
|
||||
* @param reader HistoryReader
|
||||
* @param countContacts number of contacts will search
|
||||
*/
|
||||
private void addHistorySearchProgressListeners(
|
||||
HistoryReader reader, int countContacts)
|
||||
{
|
||||
synchronized(progressListeners)
|
||||
{
|
||||
Iterator iter = progressListeners.values().iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
SearchProgressWrapper l =
|
||||
(SearchProgressWrapper) iter.next();
|
||||
l.contactCount = countContacts;
|
||||
reader.addSearchProgressListener(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the registered CallHistorySearchProgressListeners
|
||||
* from the given HistoryReader
|
||||
*
|
||||
* @param reader HistoryReader
|
||||
*/
|
||||
private void removeHistorySearchProgressListeners(HistoryReader reader)
|
||||
{
|
||||
synchronized(progressListeners)
|
||||
{
|
||||
Iterator iter = progressListeners.values().iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
SearchProgressWrapper l =
|
||||
(SearchProgressWrapper) iter.next();
|
||||
l.clear();
|
||||
reader.removeSearchProgressListener(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the history readers for the contacts in the given MetaContact
|
||||
* @param contact MetaContact
|
||||
* @return Hashtable
|
||||
*/
|
||||
private Hashtable getHistoryReaders(MetaContact contact)
|
||||
{
|
||||
Hashtable readers = new Hashtable();
|
||||
Iterator iter = contact.getContacts();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
Contact item = (Contact) iter.next();
|
||||
|
||||
try
|
||||
{
|
||||
History history = this.getHistory(null, item);
|
||||
readers.put(item, history.getReader());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
logger.error("Could not read history", e);
|
||||
}
|
||||
}
|
||||
return readers;
|
||||
}
|
||||
|
||||
/**
|
||||
* CallListener implementation for incoming calls
|
||||
* @param event CallEvent
|
||||
*/
|
||||
public void incomingCallReceived(CallEvent event)
|
||||
{
|
||||
handleNewCall(event.getSourceCall(), CallRecord.IN);
|
||||
}
|
||||
|
||||
/**
|
||||
* CallListener implementation for outgoing calls
|
||||
* @param event CallEvent
|
||||
*/
|
||||
public void outgoingCallCreated(CallEvent event)
|
||||
{
|
||||
logger.info("outgoingCallCreated");
|
||||
handleNewCall(event.getSourceCall(), CallRecord.OUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* CallListener implementation for call endings
|
||||
* @param event CallEvent
|
||||
*/
|
||||
public void callEnded(CallEvent event)
|
||||
{
|
||||
logger.info("callEnded");
|
||||
Date endTime = new Date();
|
||||
|
||||
CallRecord callRecord = findCallRecord(event.getSourceCall());
|
||||
|
||||
// no such call
|
||||
if (callRecord == null)
|
||||
return;
|
||||
|
||||
callRecord.setEndTime(endTime);
|
||||
|
||||
writeCall(callRecord, null, null);
|
||||
|
||||
currentCallRecords.remove(callRecord);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a record for joining participant
|
||||
* @param callParticipant CallParticipant
|
||||
*/
|
||||
private void handleParticipantAdded(CallParticipant callParticipant)
|
||||
{
|
||||
CallRecord callRecord = findCallRecord(callParticipant.getCall());
|
||||
|
||||
// no such call
|
||||
if(callRecord == null)
|
||||
return;
|
||||
|
||||
CallParticipantRecord newRec = new CallParticipantRecord(
|
||||
callParticipant.getAddress(),
|
||||
new Date(),
|
||||
null);
|
||||
|
||||
callRecord.getParticipantRecords().add(newRec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a record for removing participant from call
|
||||
* @param callParticipant CallParticipant
|
||||
*/
|
||||
private void handleParticipantRemoved(CallParticipant callParticipant)
|
||||
{
|
||||
logger.info("handleParticipantRemoved");
|
||||
CallRecord callRecord = findCallRecord(callParticipant.getCall());
|
||||
String pAddress = callParticipant.getAddress();
|
||||
|
||||
CallParticipantRecord cpRecord =
|
||||
callRecord.findParticipantRecord(pAddress);
|
||||
|
||||
// no such participant
|
||||
if(cpRecord == null)
|
||||
return;
|
||||
|
||||
cpRecord.setEndTime(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finding a CallRecord for the given call
|
||||
* @param call Call
|
||||
* @return CallRecord
|
||||
*/
|
||||
private CallRecord findCallRecord(Call call)
|
||||
{
|
||||
Iterator iter = currentCallRecords.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallRecord item = (CallRecord) iter.next();
|
||||
if(item.getSourceCall().equals(call))
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adding a record for a new call
|
||||
* @param sourceCall Call
|
||||
* @param direction String
|
||||
*/
|
||||
private void handleNewCall(Call sourceCall, String direction)
|
||||
{
|
||||
// if call exist. its not new
|
||||
if(currentCallRecords.contains(sourceCall))
|
||||
return;
|
||||
|
||||
CallRecord newRecord = new CallRecord(
|
||||
sourceCall,
|
||||
direction,
|
||||
new Date(),
|
||||
null);
|
||||
|
||||
sourceCall.addCallChangeListener(historyCallChangeListener);
|
||||
|
||||
currentCallRecords.add(newRecord);
|
||||
|
||||
// if has already perticipants Dispatch them
|
||||
Iterator iter = sourceCall.getCallParticipants();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipant item = (CallParticipant) iter.next();
|
||||
handleParticipantAdded(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around HistorySearchProgressListener
|
||||
* that fires events for CallHistorySearchProgressListener
|
||||
*/
|
||||
private class SearchProgressWrapper
|
||||
implements HistorySearchProgressListener
|
||||
{
|
||||
private CallHistorySearchProgressListener listener = null;
|
||||
int contactCount = 0;
|
||||
int currentContactCount = 0;
|
||||
int currentProgress = 0;
|
||||
int lastHistoryProgress = 0;
|
||||
|
||||
SearchProgressWrapper(CallHistorySearchProgressListener listener)
|
||||
{
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void progressChanged(ProgressEvent evt)
|
||||
{
|
||||
int progress = getProgressMapping(evt.getProgress());
|
||||
|
||||
listener.progressChanged(
|
||||
new net.java.sip.communicator.service.callhistory.event.
|
||||
ProgressEvent(CallHistoryServiceImpl.this, evt, progress));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the progress according the count of the contacts
|
||||
* we will search
|
||||
* @param historyProgress int
|
||||
* @return int
|
||||
*/
|
||||
private int getProgressMapping(int historyProgress)
|
||||
{
|
||||
currentProgress += (historyProgress - lastHistoryProgress)/contactCount;
|
||||
|
||||
if(historyProgress == HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE)
|
||||
{
|
||||
currentContactCount++;
|
||||
lastHistoryProgress = 0;
|
||||
|
||||
// this is the last one and the last event fire the max
|
||||
// there will be looses in currentProgress due to the devision
|
||||
if(currentContactCount == contactCount)
|
||||
currentProgress =
|
||||
CallHistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE;
|
||||
}
|
||||
else
|
||||
lastHistoryProgress = historyProgress;
|
||||
|
||||
return currentProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the values
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
contactCount = 0;
|
||||
currentProgress = 0;
|
||||
lastHistoryProgress = 0;
|
||||
currentContactCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Used to compare CallRecords
|
||||
* and to be ordered in TreeSet according their timestamp
|
||||
*/
|
||||
private class CallRecordComparator
|
||||
implements Comparator
|
||||
{
|
||||
public int compare(Object o1, Object o2)
|
||||
{
|
||||
return ((CallRecord)o1).getStartTime().
|
||||
compareTo(((CallRecord)o2).getStartTime());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive events for adding or removing participants from a call
|
||||
*/
|
||||
private class HistoryCallChangeListener
|
||||
implements CallChangeListener
|
||||
{
|
||||
public void callParticipantAdded(CallParticipantEvent evt)
|
||||
{
|
||||
handleParticipantAdded(evt.getSourceCallParticipant());
|
||||
}
|
||||
|
||||
public void callParticipantRemoved(CallParticipantEvent evt)
|
||||
{
|
||||
handleParticipantRemoved(evt.getSourceCallParticipant());
|
||||
}
|
||||
|
||||
public void callStateChanged(CallChangeEvent evt)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
Bundle-Activator: net.java.sip.communicator.impl.callhistory.CallHistoryActivator
|
||||
Bundle-Name: Call History Service Provider
|
||||
Bundle-Description: A bundle that implements the call history package.
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: org.ungoverned.gravity.servicebinder,
|
||||
org.osgi.framework,
|
||||
net.java.sip.communicator.service.fileaccess,
|
||||
net.java.sip.communicator.service.history,
|
||||
net.java.sip.communicator.service.history.event,
|
||||
net.java.sip.communicator.service.contactlist,
|
||||
net.java.sip.communicator.service.history.records,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.icqconstants,
|
||||
net.java.sip.communicator.service.protocol.event,
|
||||
Export-Package: net.java.sip.communicator.service.callhistory,
|
||||
net.java.sip.communicator.service.callhistory.event
|
||||
Metadata-Location: /net/java/sip/communicator/impl/msghistory/callhistory.metadata.xml
|
||||
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<bundle>
|
||||
<component class="net.java.sip.communicator.impl.msghistory.MessageHistoryServiceImpl">
|
||||
<provides service="net.java.sip.communicator.service.msghistory.MessageHistoryService"/>
|
||||
|
||||
<requires service="net.java.sip.communicator.service.configuration.ConfigurationService"
|
||||
filter=""
|
||||
policy="static"
|
||||
cardinality="1..1"
|
||||
bind-method="setConfigurationService"
|
||||
unbind-method="unsetConfigurationService" />
|
||||
|
||||
<requires service="net.java.sip.communicator.service.history.HistoryService"
|
||||
filter=""
|
||||
policy="static"
|
||||
cardinality="1..1"
|
||||
bind-method="setHistoryService"
|
||||
unbind-method="unsetHistoryService" />
|
||||
|
||||
<requires service="net.java.sip.communicator.service.protocol.ProtocolProviderService"
|
||||
filter=""
|
||||
cardinality="1..n"
|
||||
policy="dynamic"
|
||||
bind-method="addProtocolProvider"
|
||||
unbind-method="removeProtocolProvider" />
|
||||
|
||||
</component>
|
||||
</bundle>
|
||||
@ -0,0 +1,161 @@
|
||||
package net.java.sip.communicator.impl.protocol.mock;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.impl.protocol.sip.CallParticipantSipImpl;
|
||||
import net.java.sip.communicator.util.Logger;
|
||||
|
||||
/**
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MockCall
|
||||
extends Call
|
||||
implements CallParticipantListener
|
||||
{
|
||||
private static final Logger logger = Logger.getLogger(MockCall.class);
|
||||
|
||||
/**
|
||||
* A list containing all <tt>CallParticipant</tt>s of this call.
|
||||
*/
|
||||
private Vector callParticipants = new Vector();
|
||||
|
||||
/**
|
||||
* The state that this call is currently in.
|
||||
*/
|
||||
private CallState callState = CallState.CALL_INITIALIZATION;
|
||||
|
||||
|
||||
public MockCall(MockProvider sourceProvider)
|
||||
{
|
||||
super(sourceProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all call participants.
|
||||
*
|
||||
* @return an Iterator over all participants currently involved in the
|
||||
* call.
|
||||
*/
|
||||
public Iterator getCallParticipants()
|
||||
{
|
||||
return callParticipants.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of participants currently associated with this call.
|
||||
*
|
||||
* @return an <tt>int</tt> indicating the number of participants
|
||||
* currently associated with this call.
|
||||
*/
|
||||
public int getCallParticipantsCount()
|
||||
{
|
||||
return callParticipants.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the state that this call is currently in.
|
||||
*
|
||||
* @return a reference to the <tt>CallState</tt> instance that the call
|
||||
* is currently in.
|
||||
*/
|
||||
public CallState getCallState()
|
||||
{
|
||||
return callState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds <tt>callParticipant</tt> to the list of participants in this call.
|
||||
* If the call participant is already included in the call, the method has
|
||||
* no effect.
|
||||
*
|
||||
* @param callParticipant the new <tt>CallParticipant</tt>
|
||||
*/
|
||||
public void addCallParticipant(MockCallParticipant callParticipant)
|
||||
{
|
||||
if(callParticipants.contains(callParticipant))
|
||||
return;
|
||||
|
||||
callParticipant.addCallParticipantListener(this);
|
||||
|
||||
this.callParticipants.add(callParticipant);
|
||||
|
||||
logger.info("Will fire participant added");
|
||||
|
||||
fireCallParticipantEvent(
|
||||
callParticipant, CallParticipantEvent.CALL_PARTICIPANT_ADDED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes <tt>callParticipant</tt> from the list of participants in this
|
||||
* call. The method has no effect if there was no such participant in the
|
||||
* call.
|
||||
*
|
||||
* @param callParticipant the <tt>CallParticipant</tt> leaving the call;
|
||||
*/
|
||||
public void removeCallParticipant(MockCallParticipant callParticipant)
|
||||
{
|
||||
if(!callParticipants.contains(callParticipant))
|
||||
return;
|
||||
|
||||
this.callParticipants.remove(callParticipant);
|
||||
callParticipant.removeCallParticipantListener(this);
|
||||
|
||||
fireCallParticipantEvent(
|
||||
callParticipant, CallParticipantEvent.CALL_PARTICIPANT_REMVOVED);
|
||||
|
||||
if(callParticipants.size() == 0)
|
||||
setCallState(CallState.CALL_ENDED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the state of this call and fires a call change event notifying
|
||||
* registered listenres for the change.
|
||||
*
|
||||
* @param newState a reference to the <tt>CallState</tt> instance that
|
||||
* the call is to enter.
|
||||
*/
|
||||
public void setCallState(CallState newState)
|
||||
{
|
||||
CallState oldState = getCallState();
|
||||
|
||||
if(oldState == newState)
|
||||
return;
|
||||
|
||||
this.callState = newState;
|
||||
|
||||
fireCallChangeEvent(
|
||||
CallChangeEvent.CALL_STATE_CHANGE, oldState, newState);
|
||||
}
|
||||
|
||||
public void participantStateChanged(CallParticipantChangeEvent evt)
|
||||
{
|
||||
if ( ( (CallParticipantState) evt.getNewValue())
|
||||
== CallParticipantState.DISCONNECTED
|
||||
|| ( (CallParticipantState) evt.getNewValue())
|
||||
== CallParticipantState.FAILED)
|
||||
{
|
||||
removeCallParticipant(
|
||||
(MockCallParticipant) evt.getSourceCallParticipant());
|
||||
}
|
||||
else if ( ( (CallParticipantState) evt.getNewValue())
|
||||
== CallParticipantState.CONNECTED
|
||||
&& getCallState().equals(CallState.CALL_INITIALIZATION))
|
||||
{
|
||||
setCallState(CallState.CALL_IN_PROGRESS);
|
||||
}
|
||||
}
|
||||
|
||||
public void participantDisplayNameChanged(CallParticipantChangeEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
public void participantAddressChanged(CallParticipantChangeEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
public void participantImageChanged(CallParticipantChangeEvent evt)
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,160 @@
|
||||
package net.java.sip.communicator.impl.protocol.mock;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.CallParticipantChangeEvent;
|
||||
|
||||
/**
|
||||
* <p> </p>
|
||||
*
|
||||
* <p> </p>
|
||||
*
|
||||
* <p> </p>
|
||||
*
|
||||
* <p> </p>
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MockCallParticipant
|
||||
extends AbstractCallParticipant
|
||||
{
|
||||
/**
|
||||
* The sip address of this participant
|
||||
*/
|
||||
private String participantAddress = null;
|
||||
|
||||
/**
|
||||
* The call participant belongs to.
|
||||
*/
|
||||
private MockCall call;
|
||||
|
||||
/**
|
||||
* A string uniquely identifying the participant.
|
||||
*/
|
||||
private String participantID;
|
||||
|
||||
/**
|
||||
* Indicates the date when is call participant passed into its current state.
|
||||
*/
|
||||
protected Date currentStateStartDate = new Date();
|
||||
|
||||
/**
|
||||
* The state of the call participant.
|
||||
*/
|
||||
protected CallParticipantState callParticipantState =
|
||||
CallParticipantState.UNKNOWN;
|
||||
|
||||
|
||||
public MockCallParticipant(String address, MockCall owningCall)
|
||||
{
|
||||
this.participantAddress = address;
|
||||
this.call = owningCall;
|
||||
|
||||
call.addCallParticipant(this);
|
||||
|
||||
//create the uid
|
||||
this.participantID = String.valueOf( System.currentTimeMillis())
|
||||
+ String.valueOf(hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a String locator for that participant.
|
||||
*
|
||||
* @return the participant's address or phone number.
|
||||
*/
|
||||
public String getAddress()
|
||||
{
|
||||
return participantAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the call that this participant belongs to.
|
||||
*
|
||||
* @return a reference to the call containing this participant.
|
||||
*/
|
||||
public Call getCall()
|
||||
{
|
||||
return call;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date (time) when this call participant acquired its
|
||||
* current status.
|
||||
*
|
||||
* @return a java.util.Date object containing the date when this call
|
||||
* participant entered its current state.
|
||||
*/
|
||||
public Date getCurrentStateStartDate()
|
||||
{
|
||||
return currentStateStartDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a human readable name representing this participant.
|
||||
*
|
||||
* @return a String containing a name for that participant.
|
||||
*/
|
||||
public String getDisplayName()
|
||||
{
|
||||
return participantAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method returns an image representation of the call participant
|
||||
* (e.g.
|
||||
*
|
||||
* @return byte[] a byte array containing the image or null if no image
|
||||
* is available.
|
||||
*/
|
||||
public byte[] getImage()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique identifier representing this participant.
|
||||
*
|
||||
* @return an identifier representing this call participant.
|
||||
*/
|
||||
public String getParticipantID()
|
||||
{
|
||||
return participantID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object representing the current state of that participant.
|
||||
*
|
||||
* @return a CallParticipantState instance representin the participant's
|
||||
* state.
|
||||
*/
|
||||
public CallParticipantState getState()
|
||||
{
|
||||
return callParticipantState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes this CallParticipant to enter the specified state. The method also
|
||||
* sets the currentStateStartDate field and fires a
|
||||
* CallParticipantChangeEvent.
|
||||
*
|
||||
* @param newState the state this call participant should enter.
|
||||
* @param reason a string that could be set to contain a human readable
|
||||
* explanation for the transition (particularly handy when moving into a
|
||||
* FAILED state).
|
||||
*/
|
||||
protected void setState(CallParticipantState newState, String reason)
|
||||
{
|
||||
CallParticipantState oldState = getState();
|
||||
|
||||
if(oldState == newState)
|
||||
return;
|
||||
|
||||
this.callParticipantState = newState;
|
||||
this.currentStateStartDate = new Date();
|
||||
fireCallParticipantChangeEvent(
|
||||
CallParticipantChangeEvent.CALL_PARTICIPANT_STATE_CHANGE,
|
||||
oldState,
|
||||
newState);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,284 @@
|
||||
package net.java.sip.communicator.impl.protocol.mock;
|
||||
|
||||
import java.text.*;
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.event.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* A mock implementation of a basic telephony opearation set
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class MockOperationSetBasicTelephony
|
||||
implements OperationSetBasicTelephony,
|
||||
CallChangeListener
|
||||
{
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(MockOperationSetBasicTelephony.class);
|
||||
|
||||
/**
|
||||
* A list of listeners registered for
|
||||
* <tt>CallEvent</tt>s.
|
||||
*/
|
||||
private Vector callListeners = new Vector();
|
||||
|
||||
/**
|
||||
* A reference to the <tt>ProtocolProviderServiceSipImpl</tt> instance
|
||||
* that created us.
|
||||
*/
|
||||
private MockProvider protocolProvider = null;
|
||||
|
||||
/**
|
||||
* A table mapping call ids against call instances.
|
||||
*/
|
||||
private Hashtable activeCalls = new Hashtable();
|
||||
|
||||
|
||||
public MockOperationSetBasicTelephony(MockProvider protocolProvider)
|
||||
{
|
||||
this.protocolProvider = protocolProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified CallListener with this provider so that it
|
||||
* could be notified when incoming calls are received.
|
||||
*
|
||||
* @param listener the listener to register with this provider.
|
||||
*/
|
||||
public void addCallListener(CallListener listener)
|
||||
{
|
||||
synchronized(callListeners){
|
||||
callListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates a user request to answer an incoming call from the specified
|
||||
* CallParticipant.
|
||||
*
|
||||
* @param participant the call participant that we'd like to anwer.
|
||||
* @throws OperationFailedException with the corresponding code if we
|
||||
* encounter an error while performing this operation.
|
||||
*/
|
||||
public void answerCallParticipant(CallParticipant participant) throws
|
||||
OperationFailedException
|
||||
{
|
||||
MockCallParticipant callParticipant
|
||||
= (MockCallParticipant)participant;
|
||||
if(participant.getState().equals(CallParticipantState.CONNECTED))
|
||||
{
|
||||
logger.info("Ignoring user request to answer a CallParticipant "
|
||||
+ "that is already connected. CP:" + participant);
|
||||
return;
|
||||
}
|
||||
|
||||
callParticipant.setState(CallParticipantState.CONNECTED, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new call and invite the specified CallParticipant to it.
|
||||
*
|
||||
* @param uri the address of the callee that we should invite to a new
|
||||
* call.
|
||||
* @return CallParticipant the CallParticipant that will represented by
|
||||
* the specified uri. All following state change events will be
|
||||
* delivered through that call participant. The Call that this
|
||||
* participant is a member of could be retrieved from the
|
||||
* CallParticipatn instance with the use of the corresponding method.
|
||||
* @throws OperationFailedException with the corresponding code if we
|
||||
* fail to create the call.
|
||||
* @throws ParseException if <tt>callee</tt> is not a valid sip address
|
||||
* string.
|
||||
*/
|
||||
public Call createCall(String uri) throws OperationFailedException,
|
||||
ParseException
|
||||
{
|
||||
return createNewCall(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new call and invite the specified CallParticipant to it.
|
||||
*
|
||||
* @param callee the address of the callee that we should invite to a
|
||||
* new call.
|
||||
* @return CallParticipant the CallParticipant that will represented by
|
||||
* the specified uri. All following state change events will be
|
||||
* delivered through that call participant. The Call that this
|
||||
* participant is a member of could be retrieved from the
|
||||
* CallParticipatn instance with the use of the corresponding method.
|
||||
* @throws OperationFailedException with the corresponding code if we
|
||||
* fail to create the call.
|
||||
*/
|
||||
public Call createCall(Contact callee) throws OperationFailedException
|
||||
{
|
||||
return createNewCall(callee.getAddress());
|
||||
}
|
||||
|
||||
private Call createNewCall(String address)
|
||||
{
|
||||
MockCall newCall = new MockCall(protocolProvider);
|
||||
|
||||
newCall.addCallChangeListener(this);
|
||||
activeCalls.put(newCall.getCallID(), newCall);
|
||||
|
||||
new MockCallParticipant(address, newCall);
|
||||
|
||||
return newCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all currently active calls.
|
||||
*
|
||||
* @return Iterator
|
||||
*/
|
||||
public Iterator getActiveCalls()
|
||||
{
|
||||
return activeCalls.values().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates a user request to end a call with the specified call
|
||||
* particiapnt.
|
||||
*
|
||||
* @param participant the participant that we'd like to hang up on.
|
||||
* @throws OperationFailedException with the corresponding code if we
|
||||
* encounter an error while performing this operation.
|
||||
*/
|
||||
public void hangupCallParticipant(CallParticipant participant) throws
|
||||
OperationFailedException
|
||||
{
|
||||
//do nothing if the call is already ended
|
||||
if (participant.getState().equals(CallParticipantState.DISCONNECTED))
|
||||
{
|
||||
logger.debug("Ignoring a request to hangup a call participant "
|
||||
+"that is already DISCONNECTED");
|
||||
return;
|
||||
}
|
||||
|
||||
MockCallParticipant callParticipant
|
||||
= (MockCallParticipant)participant;
|
||||
|
||||
logger.info("hangupCallParticipant");
|
||||
callParticipant.setState(CallParticipantState.DISCONNECTED, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes communication with a call participant previously put on hold.
|
||||
*
|
||||
* @param participant the call participant to put on hold.
|
||||
* @todo Implement this
|
||||
* net.java.sip.communicator.service.protocol.OperationSetBasicTelephony
|
||||
* method
|
||||
*/
|
||||
public void putOffHold(CallParticipant participant)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the specified CallParticipant "on hold".
|
||||
*
|
||||
* @param participant the participant that we'd like to put on hold.
|
||||
* @throws OperationFailedException with the corresponding code if we
|
||||
* encounter an error while performing this operation.
|
||||
* @todo Implement this
|
||||
* net.java.sip.communicator.service.protocol.OperationSetBasicTelephony
|
||||
* method
|
||||
*/
|
||||
public void putOnHold(CallParticipant participant) throws
|
||||
OperationFailedException
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified listener from the list of call listeners.
|
||||
*
|
||||
* @param listener the listener to unregister.
|
||||
*/
|
||||
public void removeCallListener(CallListener listener)
|
||||
{
|
||||
synchronized(callListeners){
|
||||
callListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public Call receiveCall(String fromAddress)
|
||||
throws Exception
|
||||
{
|
||||
Call newCall = createCall(fromAddress);
|
||||
fireCallEvent(CallEvent.CALL_RECEIVED, newCall);
|
||||
|
||||
return newCall;
|
||||
}
|
||||
|
||||
public Call placeCall(String toAddress)
|
||||
throws Exception
|
||||
{
|
||||
Call newCall = createCall(toAddress);
|
||||
fireCallEvent(CallEvent.CALL_INITIATED, newCall);
|
||||
return newCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and dispatches a <tt>CallEvent</tt> notifying registered
|
||||
* listeners that an event with id <tt>eventID</tt> has occurred on
|
||||
* <tt>sourceCall</tt>.
|
||||
*
|
||||
* @param eventID the ID of the event to dispatch
|
||||
* @param sourceCall the call on which the event has occurred.
|
||||
*/
|
||||
protected void fireCallEvent( int eventID,
|
||||
Call sourceCall)
|
||||
{
|
||||
CallEvent cEvent = new CallEvent(sourceCall, eventID);
|
||||
|
||||
logger.debug("Dispatching a CallEvent to "
|
||||
+ callListeners.size()
|
||||
+" listeners. event is: " + cEvent.toString());
|
||||
|
||||
Iterator listeners = new ArrayList(callListeners).iterator();
|
||||
|
||||
while(listeners.hasNext())
|
||||
{
|
||||
CallListener listener = (CallListener)listeners.next();
|
||||
|
||||
if(eventID == CallEvent.CALL_INITIATED)
|
||||
listener.outgoingCallCreated(cEvent);
|
||||
else if(eventID == CallEvent.CALL_RECEIVED)
|
||||
listener.incomingCallReceived(cEvent);
|
||||
else if(eventID == CallEvent.CALL_ENDED)
|
||||
listener.callEnded(cEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public CallParticipant addNewCallParticipant(Call call, String address)
|
||||
{
|
||||
return new MockCallParticipant(address, (MockCall)call);
|
||||
}
|
||||
|
||||
public void callParticipantAdded(CallParticipantEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
public void callParticipantRemoved(CallParticipantEvent evt)
|
||||
{
|
||||
}
|
||||
|
||||
public void callStateChanged(CallChangeEvent evt)
|
||||
{
|
||||
if(evt.getEventType().equals(CallChangeEvent.CALL_STATE_CHANGE)
|
||||
&& ((CallState)evt.getNewValue()).equals(CallState.CALL_ENDED))
|
||||
{
|
||||
MockCall sourceCall = (MockCall)this.activeCalls
|
||||
.remove(evt.getSourceCall().getCallID());
|
||||
|
||||
logger.trace( "Removing call " + sourceCall + " from the list of "
|
||||
+ "active calls because it entered an ENDED state");
|
||||
|
||||
fireCallEvent(CallEvent.CALL_ENDED, sourceCall);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
package net.java.sip.communicator.service.callhistory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Structure used for encapsulating data when writing or reading
|
||||
* Call History Data. Also These records are uesd for returning data
|
||||
* from the Call History Service
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class CallParticipantRecord
|
||||
{
|
||||
private String participantAddress = null;
|
||||
private Date startTime = null;
|
||||
private Date endTime = null;
|
||||
|
||||
/**
|
||||
* Creates CallParticipantRecord
|
||||
* @param participantAddress String
|
||||
* @param startTime Date
|
||||
* @param endTime Date
|
||||
*/
|
||||
public CallParticipantRecord(
|
||||
String participantAddress,
|
||||
Date startTime,
|
||||
Date endTime)
|
||||
{
|
||||
this.participantAddress = participantAddress;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* When participant diconnected from the call
|
||||
*
|
||||
* @return Date
|
||||
*/
|
||||
public Date getEndTime()
|
||||
{
|
||||
return endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The participant address
|
||||
* @return String
|
||||
*/
|
||||
public String getParticipantAddress()
|
||||
{
|
||||
return participantAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* When participant connected to the call
|
||||
* @return Date
|
||||
*/
|
||||
public Date getStartTime()
|
||||
{
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time the participant joined the call
|
||||
* @param startTime Date
|
||||
*/
|
||||
public void setStartTime(Date startTime)
|
||||
{
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the particiapnts address
|
||||
* @param participantAddress String
|
||||
*/
|
||||
public void setParticipantAddress(String participantAddress)
|
||||
{
|
||||
this.participantAddress = participantAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time participant leaves the call
|
||||
* @param endTime Date
|
||||
*/
|
||||
public void setEndTime(Date endTime)
|
||||
{
|
||||
this.endTime = endTime;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,163 @@
|
||||
package net.java.sip.communicator.service.callhistory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
|
||||
/**
|
||||
* Structure used for encapsulating data when writing or reading
|
||||
* Call History Data. Also These records are uesd for returning data
|
||||
* from the Call History Service
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class CallRecord
|
||||
{
|
||||
/**
|
||||
* Possible directions of the call
|
||||
*/
|
||||
public final static String OUT = "out";
|
||||
public final static String IN = "in";
|
||||
|
||||
private Call sourceCall = null;
|
||||
private String direction = null;
|
||||
private Vector participantRecords = new Vector();
|
||||
private Date startTime = null;
|
||||
private Date endTime = null;
|
||||
|
||||
/**
|
||||
* Creates CallRecord
|
||||
*/
|
||||
public CallRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates Call Record
|
||||
* @param sourceCall Call
|
||||
* @param direction String
|
||||
* @param startTime Date
|
||||
* @param endTime Date
|
||||
*/
|
||||
public CallRecord(
|
||||
Call sourceCall,
|
||||
String direction,
|
||||
Date startTime,
|
||||
Date endTime)
|
||||
{
|
||||
this.sourceCall = sourceCall;
|
||||
this.direction = direction;
|
||||
this.startTime = startTime;
|
||||
this.endTime = endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a Participant with the supplied address
|
||||
* @param address String
|
||||
* @return CallParticipantRecord
|
||||
*/
|
||||
public CallParticipantRecord findParticipantRecord(String address)
|
||||
{
|
||||
Iterator iter = participantRecords.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipantRecord item = (CallParticipantRecord) iter.next();
|
||||
if (item.getParticipantAddress().equals(address))
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time when the call finishes
|
||||
* If some participant has no end Time set we set it also
|
||||
* @param endTime Date
|
||||
*/
|
||||
public void setEndTime(Date endTime)
|
||||
{
|
||||
this.endTime = endTime;
|
||||
|
||||
Iterator iter = participantRecords.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipantRecord item = (CallParticipantRecord) iter.next();
|
||||
if(item.getEndTime() == null)
|
||||
item.setEndTime(endTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time when the call begins
|
||||
* @param startTime Date
|
||||
*/
|
||||
public void setStartTime(Date startTime)
|
||||
{
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The source call which this record servers
|
||||
* @param sourceCall Call
|
||||
*/
|
||||
public void setSourceCall(Call sourceCall)
|
||||
{
|
||||
this.sourceCall = sourceCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the direction of the call
|
||||
* IN or OUT
|
||||
* @param direction String
|
||||
*/
|
||||
public void setDirection(String direction)
|
||||
{
|
||||
this.direction = direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the direction of the call
|
||||
* IN or OUT
|
||||
* @return String
|
||||
*/
|
||||
public String getDirection()
|
||||
{
|
||||
return direction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time when the call has finished
|
||||
* @return Date
|
||||
*/
|
||||
public Date getEndTime()
|
||||
{
|
||||
return endTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Vector of CallParticipantRecords
|
||||
* @return Vector
|
||||
*/
|
||||
public Vector getParticipantRecords()
|
||||
{
|
||||
return participantRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Call source of this record
|
||||
* @return Call
|
||||
*/
|
||||
public Call getSourceCall()
|
||||
{
|
||||
return sourceCall;
|
||||
}
|
||||
|
||||
/**
|
||||
* The time when the call has began
|
||||
* @return Date
|
||||
*/
|
||||
public Date getStartTime()
|
||||
{
|
||||
return startTime;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.service.callhistory.event;
|
||||
|
||||
import net.java.sip.communicator.service.history.event.*;
|
||||
|
||||
/**
|
||||
* When searching into the call history a ProgressEvent is fired whenever
|
||||
* the progress is changed. Its fired through the search process
|
||||
* informing us about the current progress.
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public interface CallHistorySearchProgressListener
|
||||
{
|
||||
/**
|
||||
* The minimum value for the progress change.
|
||||
* This is value indicates that the process has started.
|
||||
*/
|
||||
public static int PROGRESS_MINIMUM_VALUE =
|
||||
HistorySearchProgressListener.PROGRESS_MINIMUM_VALUE;
|
||||
|
||||
/**
|
||||
* The maximum value for the progress change.
|
||||
* This is value indicates that the process is finished.
|
||||
*/
|
||||
public static int PROGRESS_MAXIMUM_VALUE =
|
||||
HistorySearchProgressListener.PROGRESS_MAXIMUM_VALUE;
|
||||
|
||||
/**
|
||||
* This method gets called when progress changes through the search process
|
||||
* @param evt ProgressEvent the event holding the search condition and
|
||||
* the current progress value.
|
||||
*/
|
||||
void progressChanged(ProgressEvent evt);
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.service.callhistory.event;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A "ProgressEvent" event gets delivered through the search process
|
||||
* of CallHistoryService Service.
|
||||
* The event is wrapper around the generated event from the History Service
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class ProgressEvent
|
||||
extends java.util.EventObject
|
||||
{
|
||||
private net.java.sip.communicator.service.history.event.ProgressEvent evt;
|
||||
|
||||
/**
|
||||
* The current progress that we will pass.
|
||||
*/
|
||||
private int progress = 0;
|
||||
|
||||
public ProgressEvent(
|
||||
Object source,
|
||||
net.java.sip.communicator.service.history.event.ProgressEvent evt,
|
||||
int progress)
|
||||
{
|
||||
super(source);
|
||||
|
||||
this.evt = evt;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current progress that will be fired.
|
||||
* @return int the progress value
|
||||
*/
|
||||
public int getProgress()
|
||||
{
|
||||
return progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end date in the search condition.
|
||||
* @return Date end date value
|
||||
*/
|
||||
public Date getEndDate()
|
||||
{
|
||||
return evt.getEndDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The start date in the search condition.
|
||||
* @return Date start date value
|
||||
*/
|
||||
public Date getStartDate()
|
||||
{
|
||||
return evt.getStartDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the progress that will be fired
|
||||
* @param progress int progress value
|
||||
*/
|
||||
public void setProgress(int progress)
|
||||
{
|
||||
this.progress = progress;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.callhistory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class CallHistoryServiceLick extends TestSuite implements BundleActivator {
|
||||
private static Logger logger = Logger.getLogger(CallHistoryServiceLick.class);
|
||||
|
||||
protected static BundleContext bc = null;
|
||||
|
||||
/**
|
||||
* Start the History Sevice Implementation Compatibility Kit.
|
||||
*
|
||||
* @param bundleContext
|
||||
* BundleContext
|
||||
* @throws Exception
|
||||
*/
|
||||
public void start(BundleContext bundleContext)
|
||||
throws Exception
|
||||
{
|
||||
CallHistoryServiceLick.bc = bundleContext;
|
||||
|
||||
setName("CallHistoryServiceLick");
|
||||
Hashtable properties = new Hashtable();
|
||||
properties.put("service.pid", getName());
|
||||
|
||||
addTest(TestCallHistoryService.suite());
|
||||
bundleContext.registerService(getClass().getName(), this, properties);
|
||||
|
||||
logger.debug("Successfully registered " + getClass().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* stop
|
||||
*
|
||||
* @param bundlecontext BundleContext
|
||||
* @throws Exception
|
||||
*/
|
||||
public void stop(BundleContext bundlecontext)
|
||||
throws Exception
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,353 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.slick.callhistory;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.osgi.framework.*;
|
||||
import junit.framework.*;
|
||||
import net.java.sip.communicator.impl.protocol.mock.*;
|
||||
import net.java.sip.communicator.service.callhistory.*;
|
||||
import net.java.sip.communicator.service.contactlist.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
/**
|
||||
* Tests call history.
|
||||
* First installs the MockProtocolProvider to be able to create som calls
|
||||
* The call history service stores them
|
||||
* and then tests the verious find methods - does they find the calls we have
|
||||
* already made
|
||||
*
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class TestCallHistoryService
|
||||
extends TestCase
|
||||
{
|
||||
private static final Logger logger = Logger.getLogger(TestCallHistoryService.class);
|
||||
|
||||
/**
|
||||
* The provider that we use to make a dummy server-stored contactlist
|
||||
* used for testing. The mockProvider is instantiated and registered
|
||||
* by the metacontactlist slick activator.
|
||||
*/
|
||||
public static MockProvider mockProvider = null;
|
||||
|
||||
public static MockOperationSetBasicTelephony mockBTelphonyOpSet = null;
|
||||
|
||||
private static ServiceReference callHistoryServiceRef = null;
|
||||
public static CallHistoryService callHistoryService = null;
|
||||
|
||||
/**
|
||||
* A reference to the registration of the first mock provider.
|
||||
*/
|
||||
public static ServiceRegistration mockPrServiceRegistration = null;
|
||||
|
||||
private static Date controlDate1 = null;
|
||||
private static Date controlDate2 = null;
|
||||
|
||||
/**
|
||||
* The addresses will be used in the generated mock calls
|
||||
*/
|
||||
private static Vector participantAddresses = new Vector();
|
||||
|
||||
public TestCallHistoryService(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite()
|
||||
{
|
||||
TestSuite suite = new TestSuite();
|
||||
suite.addTest(
|
||||
new TestCallHistoryService("setupContact"));
|
||||
suite.addTest(
|
||||
new TestCallHistoryService("writeRecords"));
|
||||
suite.addTest(
|
||||
new TestCallHistoryService("readRecords"));
|
||||
suite.addTest(
|
||||
new TestCallHistoryService("checkRecordCompleteness"));
|
||||
|
||||
return suite;
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception
|
||||
{
|
||||
}
|
||||
|
||||
public void setupContact()
|
||||
{
|
||||
// changes the history service target derictory
|
||||
System.setProperty("HistoryServiceDirectory", "test-callhistory");
|
||||
|
||||
mockProvider = new MockProvider("CallHistoryMockUser");
|
||||
|
||||
//store thre presence op set of the new provider into the fixture
|
||||
Map supportedOperationSets =
|
||||
mockProvider.getSupportedOperationSets();
|
||||
|
||||
mockBTelphonyOpSet =
|
||||
(MockOperationSetBasicTelephony) supportedOperationSets.get(
|
||||
OperationSetBasicTelephony.class.getName());
|
||||
|
||||
System.setProperty(MetaContactListService.PROVIDER_MASK_PROPERTY, "1");
|
||||
|
||||
Hashtable mockProvProperties = new Hashtable();
|
||||
mockProvProperties.put(ProtocolProviderFactory.PROTOCOL
|
||||
, mockProvider.getProtocolName());
|
||||
mockProvProperties.put(MetaContactListService.PROVIDER_MASK_PROPERTY,
|
||||
"1");
|
||||
|
||||
mockPrServiceRegistration =
|
||||
CallHistoryServiceLick.bc.registerService(
|
||||
ProtocolProviderService.class.getName(),
|
||||
mockProvider,
|
||||
mockProvProperties);
|
||||
logger.debug("Registered a mock protocol provider! ");
|
||||
|
||||
callHistoryServiceRef =
|
||||
CallHistoryServiceLick.bc.
|
||||
getServiceReference(CallHistoryService.class.getName());
|
||||
|
||||
callHistoryService =
|
||||
(CallHistoryService) CallHistoryServiceLick.bc.
|
||||
getService(callHistoryServiceRef);
|
||||
|
||||
// Will genarate 4 Calls with 4 different participants
|
||||
participantAddresses.add("participant_address_1");
|
||||
participantAddresses.add("participant_address_2");
|
||||
participantAddresses.add("participant_address_3");
|
||||
participantAddresses.add("participant_address_4");
|
||||
}
|
||||
|
||||
/**
|
||||
* First create calls
|
||||
*/
|
||||
public void writeRecords()
|
||||
{
|
||||
logger.info("write records ");
|
||||
|
||||
generateCall((String)participantAddresses.get(0));
|
||||
|
||||
controlDate1 = new Date();
|
||||
|
||||
generateCall((String)participantAddresses.get(1));
|
||||
|
||||
generateCall((String)participantAddresses.get(2));
|
||||
|
||||
controlDate2 = new Date();
|
||||
|
||||
generateCall((String)participantAddresses.get(3));
|
||||
}
|
||||
|
||||
private void generateCall(String participant)
|
||||
{
|
||||
try
|
||||
{
|
||||
Call newCall = mockBTelphonyOpSet.placeCall(participant);
|
||||
|
||||
Vector v = new Vector();
|
||||
|
||||
Iterator iter = newCall.getCallParticipants();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipant item = (CallParticipant) iter.next();
|
||||
v.add(item);
|
||||
}
|
||||
|
||||
waitSeconds(2000);
|
||||
|
||||
iter = v.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipant item = (CallParticipant) iter.next();
|
||||
mockBTelphonyOpSet.hangupCallParticipant(item);
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
logger.error("Cannot place mock call", ex1);
|
||||
fail("Cannot place mock call to " + participant);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void waitSeconds(long secs)
|
||||
{
|
||||
Object lock = new Object();
|
||||
synchronized (lock){
|
||||
// wait a moment
|
||||
try{
|
||||
lock.wait(secs);
|
||||
}
|
||||
catch (InterruptedException ex){}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tests all read methods (finders)
|
||||
*/
|
||||
public void readRecords()
|
||||
{
|
||||
/**
|
||||
* This must match also many calls, as tests are run many times
|
||||
* but the minimum is 3
|
||||
*/
|
||||
Collection rs = callHistoryService.findByEndDate(controlDate2);
|
||||
Iterator resultIter = rs.iterator();
|
||||
|
||||
assertTrue("Calls too few - findByEndDate", rs.size() >= 3);
|
||||
|
||||
/**
|
||||
* must find 2 calls
|
||||
*/
|
||||
rs = callHistoryService.findByPeriod(controlDate1, controlDate2);
|
||||
resultIter = rs.iterator();
|
||||
|
||||
assertEquals("Calls must be 2", rs.size(), 2);
|
||||
|
||||
CallRecord rec = (CallRecord)resultIter.next();
|
||||
CallParticipantRecord participant =
|
||||
(CallParticipantRecord)rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(1)));
|
||||
|
||||
rec = (CallRecord)resultIter.next();
|
||||
participant = (CallParticipantRecord)rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(2)));
|
||||
|
||||
/**
|
||||
* must find 1 record
|
||||
*/
|
||||
rs = callHistoryService.findByStartDate(controlDate2);
|
||||
resultIter = rs.iterator();
|
||||
|
||||
assertEquals("Calls must be 1", rs.size(), 1);
|
||||
|
||||
rec = (CallRecord)resultIter.next();
|
||||
participant = (CallParticipantRecord)rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(3)));
|
||||
|
||||
/**
|
||||
* Must return exactly the last 3 calls
|
||||
*/
|
||||
rs = callHistoryService.findLast(3);
|
||||
resultIter = rs.iterator();
|
||||
|
||||
assertEquals("Calls must be 3", rs.size(), 3);
|
||||
|
||||
rec = (CallRecord)resultIter.next();
|
||||
participant = (CallParticipantRecord) rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(1)));
|
||||
|
||||
rec = (CallRecord)resultIter.next();
|
||||
participant = (CallParticipantRecord) rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(2)));
|
||||
|
||||
rec = (CallRecord)resultIter.next();
|
||||
participant = (CallParticipantRecord) rec.getParticipantRecords().get(0);
|
||||
|
||||
assertTrue("Participant incorrect ",
|
||||
participant.getParticipantAddress().
|
||||
equals(participantAddresses.get(3)));
|
||||
}
|
||||
|
||||
public void checkRecordCompleteness()
|
||||
{
|
||||
Vector participantAddresses = new Vector();
|
||||
participantAddresses.add("some_address");
|
||||
participantAddresses.add("some_new_address");
|
||||
|
||||
try
|
||||
{
|
||||
Call newCall =
|
||||
mockBTelphonyOpSet.placeCall((String)participantAddresses.get(0));
|
||||
|
||||
Vector v = new Vector();
|
||||
|
||||
Iterator iter = newCall.getCallParticipants();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipant item = (CallParticipant) iter.next();
|
||||
v.add(item);
|
||||
}
|
||||
|
||||
waitSeconds(2000);
|
||||
|
||||
CallParticipant newParticipant =
|
||||
mockBTelphonyOpSet.addNewCallParticipant(newCall,
|
||||
(String)participantAddresses.get(1));
|
||||
|
||||
mockBTelphonyOpSet.hangupCallParticipant(newParticipant);
|
||||
|
||||
waitSeconds(2000);
|
||||
|
||||
iter = v.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
CallParticipant item = (CallParticipant) iter.next();
|
||||
mockBTelphonyOpSet.hangupCallParticipant(item);
|
||||
}
|
||||
}
|
||||
catch (Exception ex1)
|
||||
{
|
||||
logger.error("Cannot place mock call", ex1);
|
||||
fail("Cannot place mock call");
|
||||
}
|
||||
|
||||
|
||||
Collection lastCall = callHistoryService.findLast(1);
|
||||
|
||||
assertEquals("There must be 1 Call", lastCall.size(), 1);
|
||||
|
||||
CallRecord callRecord = (CallRecord)lastCall.iterator().next();
|
||||
|
||||
assertEquals("There must be 2 participants in the call",
|
||||
callRecord.getParticipantRecords().size(), 2);
|
||||
|
||||
CallParticipantRecord callP1 =
|
||||
callRecord.findParticipantRecord((String)participantAddresses.get(0));
|
||||
CallParticipantRecord callP2 =
|
||||
callRecord.findParticipantRecord((String)participantAddresses.get(1));
|
||||
|
||||
assertTrue("Second participant added after first one",
|
||||
callP2.getStartTime().after(callP1.getStartTime()));
|
||||
|
||||
assertTrue("Second participant hanguped before first one",
|
||||
callP2.getEndTime().before(callP1.getEndTime()));
|
||||
}
|
||||
|
||||
private void dumpResult(Collection c)
|
||||
{
|
||||
Iterator rs = c.iterator();
|
||||
while (rs.hasNext())
|
||||
{
|
||||
CallRecord hr = (CallRecord)rs.next();
|
||||
logger.info("----------------------");
|
||||
logger.info(hr.getParticipantRecords());
|
||||
logger.info("----------------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
Bundle-Activator: net.java.sip.communicator.slick.callhistory.CallHistoryServiceLick
|
||||
Bundle-Name: Call History Service Implementation Compatibility Kit
|
||||
Bundle-Description: A Service Implementation Compatibility Kit for the History Service
|
||||
Bundle-Vendor: sip-communicator.org
|
||||
Bundle-Version: 0.0.1
|
||||
Import-Package: junit.framework,
|
||||
net.java.sip.communicator.slick.history,
|
||||
net.java.sip.communicator.service.history.records,
|
||||
net.java.sip.communicator.service.history,
|
||||
net.java.sip.communicator.service.contactlist,
|
||||
net.java.sip.communicator.service.callhistory,
|
||||
net.java.sip.communicator.service.callhistory.event,
|
||||
net.java.sip.communicator.impl.protocol.mock,
|
||||
net.java.sip.communicator.service.protocol,
|
||||
net.java.sip.communicator.service.protocol.event,
|
||||
org.osgi.framework,
|
||||
org.w3c.dom,
|
||||
javax.xml.parsers,
|
||||
net.java.sip.communicator.util,
|
||||
net.java.sip.communicator.util.xml,
|
||||
javax.xml.transform,
|
||||
javax.xml.transform.dom,
|
||||
javax.xml.transform.stream,
|
||||
org.apache.xml.serializer,
|
||||
Export-Package: net.java.sip.communicator.slick.callhistory,
|
||||
Loading…
Reference in new issue