
org.pircbotx.UserChannelDao Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2013 Leon Blakey
*
* This file is part of PircBotX.
*
* PircBotX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PircBotX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PircBotX. If not, see .
*/
package org.pircbotx;
import static com.google.common.base.Preconditions.*;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import java.io.Closeable;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.Synchronized;
import org.apache.commons.lang3.StringUtils;
import org.pircbotx.hooks.events.UserListEvent;
import org.pircbotx.snapshot.ChannelSnapshot;
import org.pircbotx.snapshot.UserChannelDaoSnapshot;
import org.pircbotx.snapshot.UserChannelMapSnapshot;
import org.pircbotx.snapshot.UserSnapshot;
/**
* Stores and maintains relationships between users and channels. This class should
* not be directly, it is meant to be the internal storage engine.
* @see User
* @see Channel
* @author Leon Blakey
*/
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class UserChannelDao implements Closeable {
protected final PircBotX bot;
protected final Configuration.BotFactory botFactory;
protected final Locale locale;
protected final Object accessLock = new Object();
protected final UserChannelMap mainMap;
protected final EnumMap> levelsMap;
protected final BiMap userNickMap;
protected final BiMap channelNameMap;
protected final Set privateUsers;
public UserChannelDao(PircBotX bot, Configuration.BotFactory botFactory) {
this.bot = bot;
this.botFactory = botFactory;
this.locale = bot.getConfiguration().getLocale();
this.mainMap = new UserChannelMap();
this.userNickMap = HashBiMap.create();
this.channelNameMap = HashBiMap.create();
this.privateUsers = new HashSet();
//Initialize levels map with a UserChannelMap for each level
this.levelsMap = Maps.newEnumMap(UserLevel.class);
for (UserLevel level : UserLevel.values())
levelsMap.put(level, new UserChannelMap());
}
@Synchronized("accessLock")
public U getUser(String nick) {
checkArgument(StringUtils.isNotBlank(nick), "Cannot get a blank user");
U user = userNickMap.get(nick.toLowerCase(locale));
if (user != null)
return user;
//Create new user
user = (U) botFactory.createUser(bot, nick);
userNickMap.put(nick.toLowerCase(locale), user);
return user;
}
@Synchronized("accessLock")
public boolean userExists(String nick) {
return userNickMap.containsKey(nick.toLowerCase(locale));
}
/**
* Get all user's in the channel. There are some important things to note about this method:
*
* - This method may not return a full list of users if you call it
* before the complete nick list has arrived from the IRC server.
* - If you wish to find out which users are in a channel as soon
* as you join it, then you should listen for a {@link UserListEvent}
* instead of calling this method, as the {@link UserListEvent} is only
* dispatched as soon as the full user list has been received.
* - This method will return immediately, as it does not require any
* interaction with the IRC server.
*
*
* @since PircBot 1.0.0
*
* @param chan The channel object to search in
* @return A Set of all user's in the channel
*
* @see UserListEvent
*/
@Synchronized("accessLock")
public ImmutableSortedSet getAllUsers() {
return ImmutableSortedSet.copyOf(userNickMap.values());
}
@Synchronized("accessLock")
protected void addUserToChannel(U user, C channel) {
mainMap.addUserToChannel(user, channel);
}
@Synchronized("accessLock")
protected void addUserToPrivate(U user) {
privateUsers.add(user);
}
@Synchronized("accessLock")
protected void addUserToLevel(UserLevel level, U user, C channel) {
levelsMap.get(level).addUserToChannel(user, channel);
}
@Synchronized("accessLock")
protected void removeUserFromLevel(UserLevel level, U user, C channel) {
levelsMap.get(level).removeUserFromChannel(user, channel);
}
@Synchronized("accessLock")
public ImmutableSortedSet getNormalUsers(C channel) {
Set remainingUsers = new HashSet(mainMap.getUsers(channel));
for (UserChannelMap curLevelMap : levelsMap.values())
remainingUsers.removeAll(curLevelMap.getUsers(channel));
return ImmutableSortedSet.copyOf(remainingUsers);
}
@Synchronized("accessLock")
public ImmutableSortedSet getUsers(C channel, UserLevel level) {
return levelsMap.get(level).getUsers(channel);
}
@Synchronized("accessLock")
public ImmutableSortedSet getLevels(C channel, U user) {
ImmutableSortedSet.Builder builder = ImmutableSortedSet.naturalOrder();
for (Map.Entry> curEntry : levelsMap.entrySet())
if (curEntry.getValue().containsEntry(user, channel))
builder.add(curEntry.getKey());
return builder.build();
}
@Synchronized("accessLock")
public ImmutableSortedSet getNormalUserChannels(U user) {
Set remainingChannels = new HashSet(mainMap.getChannels(user));
for (UserChannelMap curLevelMap : levelsMap.values())
remainingChannels.removeAll(curLevelMap.getChannels(user));
return ImmutableSortedSet.copyOf(remainingChannels);
}
@Synchronized("accessLock")
public ImmutableSortedSet getChannels(U user, UserLevel level) {
return levelsMap.get(level).getChannels(user);
}
@Synchronized("accessLock")
protected void removeUserFromChannel(U user, C channel) {
mainMap.removeUserFromChannel(user, channel);
for (UserChannelMap curLevelMap : levelsMap.values())
curLevelMap.removeUserFromChannel(user, channel);
if (!privateUsers.contains(user) && !mainMap.containsUser(user))
//Completely remove user
userNickMap.inverse().remove(user);
}
@Synchronized("accessLock")
protected void removeUser(U user) {
mainMap.removeUser(user);
for (UserChannelMap curLevelMap : levelsMap.values())
curLevelMap.removeUser(user);
//Remove remaining locations
userNickMap.inverse().remove(user);
privateUsers.remove(user);
}
@Synchronized("accessLock")
protected boolean levelContainsUser(UserLevel level, C channel, U user) {
return levelsMap.get(level).containsEntry(user, channel);
}
@Synchronized("accessLock")
protected void renameUser(U user, String newNick) {
user.setNick(newNick);
userNickMap.inverse().remove(user);
userNickMap.put(newNick.toLowerCase(locale), user);
}
@Synchronized("accessLock")
public C getChannel(String name) {
checkArgument(StringUtils.isNotBlank(name), "Cannot get a blank channel");
C chan = channelNameMap.get(name.toLowerCase(locale));
if (chan != null)
return chan;
//Channel does not exist, create one
chan = (C) botFactory.createChannel(bot, name);
channelNameMap.put(name.toLowerCase(locale), chan);
return chan;
}
/**
* Check if the bot is currently in the given channel.
* @param name A channel name as a string
* @return True if we are still connected to the channel, false if not
*/
@Synchronized("accessLock")
public boolean channelExists(String name) {
return channelNameMap.containsKey(name.toLowerCase(locale));
}
@Synchronized("accessLock")
public ImmutableSortedSet getUsers(C channel) {
return mainMap.getUsers(channel);
}
@Synchronized("accessLock")
public ImmutableSortedSet getAllChannels() {
return ImmutableSortedSet.copyOf(channelNameMap.values());
}
@Synchronized("accessLock")
public ImmutableSortedSet getChannels(U user) {
return mainMap.getChannels(user);
}
@Synchronized("accessLock")
protected void removeChannel(C channel) {
mainMap.removeChannel(channel);
for (UserChannelMap curLevelMap : levelsMap.values())
curLevelMap.removeChannel(channel);
//Remove remaining locations
channelNameMap.inverse().remove(channel);
}
@Synchronized("accessLock")
public void close() {
mainMap.clear();
for (UserChannelMap curLevelMap : levelsMap.values())
curLevelMap.clear();
channelNameMap.clear();
privateUsers.clear();
userNickMap.clear();
}
@Synchronized("accessLock")
public UserChannelDaoSnapshot createSnapshot() {
//Create snapshots of all users and channels
ImmutableMap.Builder userSnapshotBuilder = ImmutableMap.builder();
for (U curUser : userNickMap.values())
userSnapshotBuilder.put(curUser, curUser.createSnapshot());
ImmutableMap userSnapshotMap = userSnapshotBuilder.build();
ImmutableMap.Builder channelSnapshotBuilder = ImmutableMap.builder();
for (C curChannel : channelNameMap.values())
channelSnapshotBuilder.put(curChannel, curChannel.createSnapshot());
ImmutableMap channelSnapshotMap = channelSnapshotBuilder.build();
//Make snapshots of the relationship maps using the above user and channel snapshots
UserChannelMapSnapshot mainMapSnapshot = mainMap.createSnapshot(userSnapshotMap, channelSnapshotMap);
EnumMap> levelsMapSnapshot = Maps.newEnumMap(UserLevel.class);
for (Map.Entry> curLevel : levelsMap.entrySet())
levelsMapSnapshot.put(curLevel.getKey(), curLevel.getValue().createSnapshot(userSnapshotMap, channelSnapshotMap));
ImmutableBiMap.Builder userNickMapSnapshotBuilder = ImmutableBiMap.builder();
for (Map.Entry curNick : userNickMap.entrySet())
userNickMapSnapshotBuilder.put(curNick.getKey(), curNick.getValue().createSnapshot());
ImmutableBiMap.Builder channelNameMapSnapshotBuilder = ImmutableBiMap.builder();
for (Map.Entry curName : channelNameMap.entrySet())
channelNameMapSnapshotBuilder.put(curName.getKey(), curName.getValue().createSnapshot());
ImmutableSortedSet.Builder privateUserSnapshotBuilder = ImmutableSortedSet.naturalOrder();
for (User curUser : privateUsers)
privateUserSnapshotBuilder.add(curUser.createSnapshot());
//Finally can create the snapshot object
UserChannelDaoSnapshot daoSnapshot = new UserChannelDaoSnapshot(bot,
locale,
mainMapSnapshot,
levelsMapSnapshot,
userNickMapSnapshotBuilder.build(),
channelNameMapSnapshotBuilder.build(),
privateUserSnapshotBuilder.build());
//Tell UserSnapshots and ChannelSnapshots what the new backing dao is
for(UserSnapshot curUserSnapshot : userSnapshotMap.values())
curUserSnapshot.setDao(daoSnapshot);
for(ChannelSnapshot curChannelSnapshot : channelSnapshotMap.values())
curChannelSnapshot.setDao(daoSnapshot);
//Finally
return daoSnapshot;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy