001/*
002 * GWTEventService
003 * Copyright (c) 2011 and beyond, strawbill UG (haftungsbeschr?nkt)
004 *
005 * This is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU Lesser General Public License as
007 * published by the Free Software Foundation; either version 3 of
008 * the License, or (at your option) any later version.
009 * Other licensing for GWTEventService may also be possible on request.
010 * Please view the license.txt of the project for more information.
011 *
012 * This software is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this software; if not, write to the Free
019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021 */
022package de.novanic.eventservice.service.registry.user;
023
024import de.novanic.eventservice.client.event.domain.Domain;
025
026import java.util.Set;
027import java.util.HashSet;
028import java.util.Map;
029import java.util.concurrent.ConcurrentMap;
030import java.util.concurrent.ConcurrentHashMap;
031
032/**
033 * DomainUserMapping manages the allocation of users ({@link de.novanic.eventservice.service.registry.user.UserInfo}) to domains
034 * ({@link de.novanic.eventservice.client.event.domain.Domain}) and provides several methods for access and modifications.
035 *
036 * @author sstrohschein
037 *         <br>Date: 09.09.2009
038 *         <br>Time: 15:04:36
039 */
040public class DomainUserMapping
041{
042    private final ConcurrentMap<Domain, ConcurrentMap<UserInfo, UserInfo>> myDomainUserInfoMap;
043
044    /**
045     * Creates a new, empty DomainUserMapping.
046     */
047    public DomainUserMapping() {
048        myDomainUserInfoMap = new ConcurrentHashMap<Domain, ConcurrentMap<UserInfo, UserInfo>>();
049    }
050
051    /**
052     * Adds a new user to a domain and creates a new domain entry when the domain is new to the DomainUserMapping.
053     * @param aDomain domain to add the user to
054     * @param aUserInfo user
055     */
056    public void addUser(Domain aDomain, UserInfo aUserInfo) {
057        ConcurrentMap<UserInfo, UserInfo> theUsers = myDomainUserInfoMap.get(aDomain);
058        if(theUsers == null) {
059            ConcurrentMap<UserInfo, UserInfo> theNewUsers = new ConcurrentHashMap<UserInfo, UserInfo>();
060            theUsers = myDomainUserInfoMap.putIfAbsent(aDomain, theNewUsers);
061            if(theUsers == null) {
062                theUsers = theNewUsers;
063            }
064        }
065        theUsers.putIfAbsent(aUserInfo, aUserInfo);
066    }
067
068    /**
069     * Removes a user from all domains and removes the domains when no other users are added to the domain.
070     * @param aUserInfo user
071     */
072    public void removeUser(UserInfo aUserInfo) {
073        for(Map.Entry<Domain, ConcurrentMap<UserInfo, UserInfo>> theDomainUsersEntry: myDomainUserInfoMap.entrySet()) {
074            Domain theDomain = theDomainUsersEntry.getKey();
075            ConcurrentMap<UserInfo, UserInfo> theDomainUsers = theDomainUsersEntry.getValue();
076            removeUser(theDomain, theDomainUsers, aUserInfo);
077        }
078    }
079
080    /**
081     * Removes a user from a specified domain and removes the domain when no other users are added to the domain.
082     * @param aDomain domain
083     * @param aUserInfo user
084     * @return true when the user is removed from the domain, otherwise false
085     */
086    public boolean removeUser(Domain aDomain, UserInfo aUserInfo) {
087        boolean isUserRemoved = false;
088
089        if(aDomain != null && aUserInfo != null) {
090            ConcurrentMap<UserInfo, UserInfo> theDomainUsers = myDomainUserInfoMap.get(aDomain);
091            if(theDomainUsers != null) {
092                isUserRemoved = removeUser(aDomain, theDomainUsers, aUserInfo);
093            }
094        }
095        return isUserRemoved;
096    }
097
098    /**
099     * Removes a user from a specified domain and removes the domain when no other users are added to the domain.
100     * @param aDomain domain
101     * @param aDomainUsers users of the domain
102     * @param aUser user
103     * @return true when the user is removed from the domain, otherwise false
104     */
105    private boolean removeUser(Domain aDomain, ConcurrentMap<UserInfo, UserInfo> aDomainUsers, UserInfo aUser) {
106        boolean isUserRemoved = (aDomainUsers.remove(aUser) != null);
107        if(isUserRemoved) {
108            if(aDomainUsers.isEmpty()) {
109                //Atomic operation to remove only when the collection is empty. Otherwise another thread could add a user between the check of is empty and remove.
110                //isEmpty is checked before for more performance for the most cases.
111                myDomainUserInfoMap.remove(aDomain, aDomainUsers);
112            }
113        }
114        return isUserRemoved;
115    }
116
117    /**
118     * Returns all domains which have added users
119     * @return all domains which have added users
120     */
121    public Set<Domain> getDomains() {
122        return myDomainUserInfoMap.keySet();
123    }
124
125    /**
126     * Returns all domains to a user.
127     * @param aUserInfo user
128     * @return all domains where the user is added
129     */
130    public Set<Domain> getDomains(UserInfo aUserInfo) {
131        if(aUserInfo != null) {
132            Set<Domain> theDomains = new HashSet<Domain>(myDomainUserInfoMap.size());
133
134            for(Map.Entry<Domain, ConcurrentMap<UserInfo, UserInfo>> theDomainUserEntry : myDomainUserInfoMap.entrySet()) {
135                ConcurrentMap<UserInfo, UserInfo> theDomainUsers = theDomainUserEntry.getValue();
136                if(theDomainUsers.containsKey(aUserInfo)) {
137                    theDomains.add(theDomainUserEntry.getKey());
138                }
139            }
140            return theDomains;
141        }
142        return new HashSet<Domain>(0);
143    }
144
145    /**
146     * Returns all users of a domain.
147     * @param aDomain domain
148     * @return all users of the domain
149     */
150    public Set<UserInfo> getUsers(Domain aDomain) {
151        if(aDomain != null) {
152            final ConcurrentMap<UserInfo, UserInfo> theUserInfoCollection = myDomainUserInfoMap.get(aDomain);
153            if(theUserInfoCollection != null) {
154                return new HashSet<UserInfo>(theUserInfoCollection.keySet());
155            }
156            return new HashSet<UserInfo>(0);
157        }
158        return null;
159    }
160
161    /**
162     * Checks if a user is added to a domain.
163     * @param aUserInfo user
164     * @return true when the user is added to a domain, otherwise false
165     */
166    public boolean isUserContained(UserInfo aUserInfo) {
167        for(ConcurrentMap<UserInfo, UserInfo> theDomainUsers: myDomainUserInfoMap.values()) {
168            if(theDomainUsers.containsKey(aUserInfo)) {
169                return true;
170            }
171        }
172        return false;
173    }
174
175    /**
176     * Checks if a user is added to the domain.
177     * @param aDomain domain
178     * @param aUserInfo user
179     * @return true when the user is added to the domain, otherwise false
180     */
181    public boolean isUserContained(Domain aDomain, UserInfo aUserInfo) {
182        ConcurrentMap<UserInfo, UserInfo> theDomainUsers = myDomainUserInfoMap.get(aDomain);
183        return theDomainUsers != null && theDomainUsers.containsKey(aUserInfo);
184    }
185}