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.DomainEvent;
025import de.novanic.eventservice.client.event.Event;
026import de.novanic.eventservice.client.event.DefaultDomainEvent;
027import de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent;
028import de.novanic.eventservice.client.event.listener.unlisten.DefaultUnlistenEvent;
029import de.novanic.eventservice.client.event.filter.EventFilter;
030import de.novanic.eventservice.client.event.domain.Domain;
031import de.novanic.eventservice.util.PlatformUtil;
032
033import java.util.*;
034import java.util.concurrent.ConcurrentLinkedQueue;
035import java.util.concurrent.ConcurrentHashMap;
036
037/**
038 * UserInfo is a class to represent all users/clients and to manage all their information.
039 * It holds the events, the EventFilters ({@link de.novanic.eventservice.client.event.filter.EventFilter}) and the last
040 * activity time for the user.
041 *
042 * @author sstrohschein
043 *         <br>Date: 19.01.2009
044 *         <br>Time: 23:59:58
045 */
046public class UserInfo implements Comparable<UserInfo>
047{
048    private final String myUserId;
049    private final Queue<DomainEvent> myEvents;
050    private final Map<Domain, EventFilter> myDomainEventFilters;
051    private UnlistenEvent myUnlistenEvent;
052    private volatile long myLastActivityTime;
053
054    /**
055     * Creates a new UserInfo for the user id.
056     * @param aUserId user
057     */
058    public UserInfo(String aUserId) {
059        myUserId = aUserId;
060        myEvents = new ConcurrentLinkedQueue<DomainEvent>();
061        myDomainEventFilters = new ConcurrentHashMap<Domain, EventFilter>();
062        myLastActivityTime = PlatformUtil.getCurrentTime();
063    }
064
065    /**
066     * Returns the user id.
067     * @return user / user id
068     */
069    public String getUserId() {
070        return myUserId;
071    }
072
073    /**
074     * Adds an event for a domain to the user.
075     * @param aDomain domain
076     * @param anEvent event
077     */
078    public void addEvent(Domain aDomain, Event anEvent) {
079        DomainEvent theDomainEvent = new DefaultDomainEvent(anEvent, aDomain);
080        myEvents.add(theDomainEvent);
081        notifyEventListening();
082    }
083
084    /**
085     * doNotifyAll informs all waiting Threads for new events.
086     */
087    public synchronized void notifyEventListening() {
088        notifyAll();
089    }
090
091    /**
092     * Returns and removes all recorded events.
093     * @param aMaxEvents maximum amount of events which should be processed (at once).
094     *                   The rest will be processed with the next call/request (again to the maximum amount, of course).
095     *                   The maximum amount of events prevents the logic from endless seeking of events (for example when more events are concurrently added than this logic/thread can process).
096     * @return all events according to the user
097     */
098    public List<DomainEvent> retrieveEvents(int aMaxEvents) {
099        List<DomainEvent> theEventList = new ArrayList<DomainEvent>(myEvents.size());
100        DomainEvent theEvent;
101        for(int i = 0; i < aMaxEvents && (theEvent = myEvents.poll()) != null; i++) {
102            theEventList.add(theEvent);
103        }
104        return theEventList;
105    }
106
107    /**
108     * Checks if events are available.
109     * @return true when no events recognized, otherwise false
110     */
111    public boolean isEventsEmpty() {
112        return myEvents.isEmpty();
113    }
114
115    /**
116     * Sets an EventFilter to a domain.
117     * @param aDomain domain where the EventFilter should be applied.
118     * @param anEventFilter EventFilter to filter the events for the domain
119     */
120    public void setEventFilter(final Domain aDomain, EventFilter anEventFilter) {
121        if(anEventFilter != null) {
122            myDomainEventFilters.put(aDomain, anEventFilter);
123        }
124    }
125
126    /**
127     * Removes the EventFilter for a domain.
128     * @param aDomain domain where the EventFilter to remove is applied.
129     * @return true when the {@link de.novanic.eventservice.client.event.filter.EventFilter} is removed, otherwise false
130     * (for example the {@link de.novanic.eventservice.client.event.filter.EventFilter} was already removed before)
131     */
132    public boolean removeEventFilter(final Domain aDomain) {
133        return aDomain != null && myDomainEventFilters.remove(aDomain) != null;
134    }
135
136    /**
137     * Returns the EventFilter for the domain.
138     * @param aDomain domain
139     * @return EventFilter for the domain
140     */
141    public EventFilter getEventFilter(Domain aDomain) {
142        if(aDomain != null) {
143            return myDomainEventFilters.get(aDomain);
144        }
145        return null;
146    }
147
148    /**
149     * Returns the registered {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent}. That can be
150     * a custom {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} which can be set with
151     * {@link de.novanic.eventservice.service.registry.user.UserInfo#setUnlistenEvent(de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent)}
152     * or a default/generic {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} when no custom
153     * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} is registered.
154     * @return {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} to report a timeout or
155     * a user/client which left a domain.
156     */
157    public UnlistenEvent getUnlistenEvent() {
158        if(myUnlistenEvent == null) {
159            return new DefaultUnlistenEvent();//create here on request/unlisten to save memory
160        }
161        return myUnlistenEvent;
162    }
163
164    /**
165     * A custom {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} can be set which is transferred
166     * to all registered {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} instances when
167     * an unlisten occurred (for example by a timeout or when a user/client leaves a domain). When no custom
168     * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} is registered, a default/generic
169     * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} will be processed and reported.
170     * @param anUnlistenEvent {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} which should be
171     * triggered.
172     */
173    public void setUnlistenEvent(UnlistenEvent anUnlistenEvent) {
174        myUnlistenEvent = anUnlistenEvent;
175    }
176
177    /**
178     * Sets the last activity time. The last activity is used to recognize timeouts.
179     * @param aLastActivityTime last activity time
180     */
181    public void setLastActivityTime(long aLastActivityTime) {
182        myLastActivityTime = aLastActivityTime;
183    }
184
185    /**
186     *  Returns the last activity time. The last activity is used to recognize timeouts.
187     * @return last activity time
188     */
189    public long getLastActivityTime() {
190        return myLastActivityTime;
191    }
192
193    /**
194     * That method must be called to report a user activity and protects the user from a timeout for the time of the
195     * timeout interval ({@link de.novanic.eventservice.config.EventServiceConfiguration#getTimeoutTime()}).
196     */
197    public void reportUserActivity() {
198        setLastActivityTime(PlatformUtil.getCurrentTime());
199    }
200
201    public int compareTo(UserInfo aUserInfo) {
202        return myUserId.compareTo(aUserInfo.myUserId);
203    }
204
205    public boolean equals(Object anObject) {
206        if(this == anObject) {
207            return true;
208        }
209        if(anObject == null || getClass() != anObject.getClass()) {
210            return false;
211        }
212        UserInfo theOtherUserInfo = (UserInfo)anObject;
213        return myUserId.equals(theOtherUserInfo.myUserId);
214    }
215
216    public int hashCode() {
217        return myUserId.hashCode();
218    }
219
220    /**
221     * The user id is used to represent the UserInfo.
222     * @return String representation (user id) of the UserInfo.
223     */
224    public String toString() {
225        return getUserId();
226    }
227}