org.asteriskjava.live.internal.MeetMeManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of asterisk-java Show documentation
Show all versions of asterisk-java Show documentation
The free Java library for Asterisk PBX integration.
The newest version!
/*
* Copyright 2004-2006 Stefan Reuter
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.asteriskjava.live.internal;
import org.asteriskjava.live.ManagerCommunicationException;
import org.asteriskjava.live.MeetMeRoom;
import org.asteriskjava.lock.LockableMap;
import org.asteriskjava.lock.Locker.LockCloser;
import org.asteriskjava.manager.action.CommandAction;
import org.asteriskjava.manager.event.AbstractMeetMeEvent;
import org.asteriskjava.manager.event.MeetMeLeaveEvent;
import org.asteriskjava.manager.event.MeetMeMuteEvent;
import org.asteriskjava.manager.event.MeetMeTalkingEvent;
import org.asteriskjava.manager.response.CommandResponse;
import org.asteriskjava.manager.response.ManagerError;
import org.asteriskjava.manager.response.ManagerResponse;
import org.asteriskjava.util.DateUtil;
import org.asteriskjava.util.Log;
import org.asteriskjava.util.LogFactory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Manages MeetMe events on behalf of an AsteriskServer.
*
* @author srt
*/
class MeetMeManager {
private static final String MEETME_LIST_COMMAND = "meetme list";
private static final Pattern MEETME_LIST_PATTERN = Pattern.compile("^User #: ([0-9]+).*Channel: (\\S+).*$");
private final Log logger = LogFactory.getLog(getClass());
private final AsteriskServerImpl server;
private final ChannelManager channelManager;
/**
* Maps room number to MeetMe room.
*/
private final LockableMap rooms;
MeetMeManager(AsteriskServerImpl server, ChannelManager channelManager) {
this.server = server;
this.channelManager = channelManager;
this.rooms = new LockableMap<>(new HashMap<>());
}
void initialize() {
try (LockCloser closer = rooms.withLock()) {
for (MeetMeRoomImpl room : rooms.values()) {
populateRoom(room);
}
}
}
void disconnected() {
/*
* try (LockCloser closer = Locker2.lock(rooms) { rooms.clear(); }
*/
}
Collection getMeetMeRooms() {
final Collection result;
result = new ArrayList<>();
try (LockCloser closer = rooms.withLock()) {
for (MeetMeRoom room : rooms.values()) {
if (!room.isEmpty()) {
result.add(room);
}
}
}
return result;
}
void handleMeetMeEvent(AbstractMeetMeEvent event) {
String roomNumber;
Integer userNumber;
AsteriskChannelImpl channel;
MeetMeRoomImpl room;
MeetMeUserImpl user;
roomNumber = event.getMeetMe();
if (roomNumber == null) {
logger.warn("RoomNumber (meetMe property) is null. Ignoring " + event.getClass().getName());
return;
}
userNumber = event.getUser();
if (userNumber == null) {
logger.warn("UserNumber (userNum property) is null. Ignoring " + event.getClass().getName());
return;
}
user = getOrCreateUserImpl(event);
if (user == null) {
return;
}
channel = user.getChannel();
room = user.getRoom();
if (event instanceof MeetMeLeaveEvent) {
logger.info("Removing channel " + channel.getName() + " from room " + roomNumber);
if (room != user.getRoom()) {
if (user.getRoom() != null) {
logger.error("Channel " + channel.getName() + " should be removed from room " + roomNumber
+ " but is user of room " + user.getRoom().getRoomNumber());
user.getRoom().removeUser(user);
} else {
logger.error("Channel " + channel.getName() + " should be removed from room " + roomNumber
+ " but is user of no room");
}
}
// Mmmm should remove from the room before firing
// PropertyChangeEvents ?
user.left(event.getDateReceived());
room.removeUser(user);
channel.setMeetMeUserImpl(null);
} else if (event instanceof MeetMeTalkingEvent) {
Boolean status;
status = ((MeetMeTalkingEvent) event).getStatus();
if (status != null) {
user.setTalking(status);
} else {
user.setTalking(true);
}
} else if (event instanceof MeetMeMuteEvent) {
Boolean status;
status = ((MeetMeMuteEvent) event).getStatus();
if (status != null) {
user.setMuted(status);
}
}
}
private void populateRoom(MeetMeRoomImpl room) {
final CommandAction meetMeListAction;
final ManagerResponse response;
final List lines;
final Collection userNumbers = new ArrayList<>(); // list
// of
// user
// numbers
// in
// the
// room
meetMeListAction = new CommandAction(MEETME_LIST_COMMAND + " " + room.getRoomNumber());
try {
response = server.sendAction(meetMeListAction);
} catch (ManagerCommunicationException e) {
logger.error("Unable to send \"" + MEETME_LIST_COMMAND + "\" command", e);
return;
}
if (response instanceof ManagerError) {
logger.error("Unable to send \"" + MEETME_LIST_COMMAND + "\" command: " + response.getMessage());
return;
}
if (!(response instanceof CommandResponse)) {
logger.error("Response to \"" + MEETME_LIST_COMMAND + "\" command is not a CommandResponse but "
+ response.getClass());
return;
}
lines = ((CommandResponse) response).getResult();
for (String line : lines) {
final Matcher matcher;
final Integer userNumber;
final AsteriskChannelImpl channel;
boolean muted = false;
boolean talking = false;
MeetMeUserImpl channelUser;
MeetMeUserImpl roomUser;
matcher = MEETME_LIST_PATTERN.matcher(line);
if (!matcher.matches()) {
continue;
}
userNumber = Integer.valueOf(matcher.group(1));
channel = channelManager.getChannelImplByName(matcher.group(2));
if (channel == null) // User has left the room already in the
// meanwhile
{
continue;
}
userNumbers.add(userNumber);
if (line.contains("(Admin Muted)") || line.contains("(Muted)")) {
muted = true;
}
if (line.contains("(talking)")) {
talking = true;
}
channelUser = channel.getMeetMeUser();
if (channelUser != null && channelUser.getRoom() != room) {
channelUser.left(DateUtil.getDate());
channelUser = null;
}
roomUser = room.getUser(userNumber);
if (roomUser != null && roomUser.getChannel() != channel) {
room.removeUser(roomUser);
roomUser = null;
}
if (channelUser == null && roomUser == null) {
final MeetMeUserImpl user;
// using the current date as dateJoined is not correct but we
// don't have anything that is better
user = new MeetMeUserImpl(server, room, userNumber, channel, DateUtil.getDate());
user.setMuted(muted);
user.setTalking(talking);
room.addUser(user);
channel.setMeetMeUserImpl(user);
server.fireNewMeetMeUser(user);
} else if (channelUser != null && roomUser == null) {
channelUser.setMuted(muted);
room.addUser(channelUser);
} else if (channelUser == null && roomUser != null) {
roomUser.setMuted(muted);
channel.setMeetMeUserImpl(roomUser);
} else {
if (channelUser != roomUser) {
logger.error("Inconsistent state: channelUser != roomUser, channelUser=" + channelUser + ", roomUser="
+ roomUser);
}
}
}
Collection users = room.getUserImpls();
Collection usersToRemove = new ArrayList<>();
for (MeetMeUserImpl user : users) {
if (!userNumbers.contains(user.getUserNumber())) {
// remove user as he is no longer in the room
usersToRemove.add(user);
}
}
for (MeetMeUserImpl user : usersToRemove) {
user.left(DateUtil.getDate());
room.removeUser(user);
user.getChannel().setMeetMeUserImpl(null);
}
}
private MeetMeUserImpl getOrCreateUserImpl(AbstractMeetMeEvent event) {
final String roomNumber;
final MeetMeRoomImpl room;
final String uniqueId;
final AsteriskChannelImpl channel;
MeetMeUserImpl user;
roomNumber = event.getMeetMe();
room = getOrCreateRoomImpl(roomNumber);
user = room.getUser(event.getUser());
if (user != null) {
return user;
}
// ok create a new one
uniqueId = event.getUniqueId();
if (uniqueId == null) {
logger.warn("UniqueId is null. Ignoring MeetMeEvent");
return null;
}
channel = channelManager.getChannelImplById(uniqueId);
if (channel == null) {
logger.warn("No channel with unique id " + uniqueId + ". Ignoring MeetMeEvent");
return null;
}
user = channel.getMeetMeUser();
if (user != null) {
logger.error("Got MeetMeEvent for channel " + channel.getName() + " that is already user of a room");
user.left(event.getDateReceived());
if (user.getRoom() != null) {
user.getRoom().removeUser(user);
}
channel.setMeetMeUserImpl(null);
}
logger.info("Adding channel " + channel.getName() + " as user " + event.getUser() + " to room " + roomNumber);
user = new MeetMeUserImpl(server, room, event.getUser(), channel, event.getDateReceived());
room.addUser(user);
channel.setMeetMeUserImpl(user);
server.fireNewMeetMeUser(user);
return user;
}
/**
* Returns the room with the given number or creates a new one if none is
* there yet.
*
* @param roomNumber number of the room to get or create.
* @return the room with the given number.
*/
MeetMeRoomImpl getOrCreateRoomImpl(String roomNumber) {
MeetMeRoomImpl room;
boolean created = false;
try (LockCloser closer = rooms.withLock()) {
room = rooms.get(roomNumber);
if (room == null) {
room = new MeetMeRoomImpl(server, roomNumber);
populateRoom(room);
rooms.put(roomNumber, room);
created = true;
}
}
if (created) {
logger.debug("Created MeetMeRoom " + roomNumber);
}
return room;
}
}