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.client.event; 023 024import de.novanic.eventservice.client.connection.callback.AsyncCallbackWrapper; 025import de.novanic.eventservice.client.event.listener.EventNotification; 026import de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector; 027import de.novanic.eventservice.client.event.listener.RemoteEventListener; 028import de.novanic.eventservice.client.event.filter.EventFilter; 029import de.novanic.eventservice.client.event.domain.Domain; 030import de.novanic.eventservice.client.event.domain.DomainFactory; 031import de.novanic.eventservice.client.event.command.*; 032import de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener; 033import de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent; 034 035import java.util.*; 036 037import com.google.gwt.user.client.rpc.AsyncCallback; 038 039/** 040 * The RemoteEventService supports listening to the server via RemoteEventListeners ({@link de.novanic.eventservice.client.event.listener.RemoteEventListener}). 041 * It keeps a connection to the server. When an event occurred at the server, the RemoteEventService informs the RemoteEventListeners 042 * about the event and starts listening at the server again. When no RemoteEventListeners registered anymore, the 043 * RemoteEventService stops listening till new RemoteEventListeners are registered. 044 * The listening works with a domain/context scope. See the documentation/manual to get more information about the 045 * listening concept. 046 * 047 * @author sstrohschein 048 * <br>Date: 06.06.2008 049 * <br>Time: 18:56:46 050 */ 051public class DefaultRemoteEventService extends RemoteEventServiceAccessor implements RemoteEventService 052{ 053 private Map<Domain, List<RemoteEventListener>> myDomainListenerMapping; 054 055 /** 056 * Creates a new RemoteEventService. 057 * @param aRemoteEventConnector {@link de.novanic.eventservice.client.connection.strategy.connector.RemoteEventConnector} for the connection 058 * between client side and server side 059 */ 060 protected DefaultRemoteEventService(RemoteEventConnector aRemoteEventConnector) { 061 super(aRemoteEventConnector); 062 myDomainListenerMapping = new HashMap<Domain, List<RemoteEventListener>>(); 063 } 064 065 /** 066 * Adds a listener for a domain. 067 * It activates the RemoteEventService if it was inactive. 068 * @param aDomain domain 069 * @param aRemoteListener new listener 070 */ 071 public void addListener(Domain aDomain, RemoteEventListener aRemoteListener) { 072 addListener(aDomain, aRemoteListener, (AsyncCallback<Void>)null); 073 } 074 075 /** 076 * Adds a listener for a domain. 077 * It activates the RemoteEventService if it was inactive. 078 * @param aDomain domain 079 * @param aRemoteListener new listener 080 * @param aCallback callback (only called when no listener is already registered for the domain) 081 */ 082 public void addListener(Domain aDomain, RemoteEventListener aRemoteListener, AsyncCallback<Void> aCallback) { 083 if(addListenerLocal(aDomain, aRemoteListener)) { 084 activate(aDomain, aCallback); 085 } 086 } 087 088 /** 089 * Adds a listener for a domain. The EventFilter is applied to the domain to filter events before the 090 * RemoteEventListener recognizes the event. 091 * It activates the RemoteEventService if it was inactive. 092 * @param aDomain domain 093 * @param aRemoteListener new listener 094 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 095 */ 096 public void addListener(Domain aDomain, RemoteEventListener aRemoteListener, EventFilter anEventFilter) { 097 addListener(aDomain, aRemoteListener, anEventFilter, null); 098 } 099 100 /** 101 * Adds a listener for a domain. The EventFilter is applied to the domain to filter events before the 102 * RemoteEventListener recognizes the event. 103 * It activates the RemoteEventService if it was inactive. 104 * @param aDomain domain 105 * @param aRemoteListener new listener 106 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 107 * @param aCallback callback (only called when no listener is registered for the domain) 108 */ 109 public void addListener(Domain aDomain, RemoteEventListener aRemoteListener, EventFilter anEventFilter, AsyncCallback<Void> aCallback) { 110 if(addListenerLocal(aDomain, aRemoteListener, anEventFilter)) { 111 activate(aDomain, anEventFilter, aCallback); 112 } 113 } 114 115 /** 116 * Adds a listener for a domain. 117 * @param aDomain domain 118 * @param aRemoteListener new listener 119 * @return true, when it is a new / unregistered domain for the client, otherwise false 120 */ 121 private boolean addListenerLocal(Domain aDomain, RemoteEventListener aRemoteListener) { 122 return addListenerLocal(aDomain, aRemoteListener, null); 123 } 124 125 /** 126 * Adds a listener for a domain. The EventFilter is applied to the domain to filter events before the 127 * RemoteEventListener recognizes the event. 128 * @param aDomain domain 129 * @param aRemoteListener new listener 130 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 131 * @return true, when it is a new / unregistered domain for the client, otherwise false 132 */ 133 private boolean addListenerLocal(Domain aDomain, RemoteEventListener aRemoteListener, EventFilter anEventFilter) { 134 List<RemoteEventListener> theListeners = myDomainListenerMapping.get(aDomain); 135 final boolean isNewDomain = theListeners == null; 136 if(isNewDomain) { 137 theListeners = new ArrayList<RemoteEventListener>(); 138 } else if(anEventFilter != null) { 139 registerEventFilter(aDomain, anEventFilter); 140 } 141 theListeners = addOnCopy(theListeners, aRemoteListener); 142 myDomainListenerMapping.put(aDomain, theListeners); 143 return isNewDomain; 144 } 145 146 /** 147 * Registers an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} to listen for all 148 * user/client domain deregistrations and timeouts. The scope for unlisten events to receive is set to 149 * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener.Scope#UNLISTEN} by default. 150 * To use other scopes see 151 * {@link de.novanic.eventservice.client.event.RemoteEventService#addUnlistenListener(de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener.Scope, de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener, com.google.gwt.user.client.rpc.AsyncCallback)}. 152 * @param anUnlistenEventListener {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 153 * to listen for all user/client domain deregistrations and timeouts. 154 * @param aCallback callback 155 */ 156 public void addUnlistenListener(UnlistenEventListener anUnlistenEventListener, AsyncCallback<Void> aCallback) { 157 addUnlistenListener(UnlistenEventListener.Scope.UNLISTEN, anUnlistenEventListener, aCallback); 158 } 159 160 /** 161 * Registers an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} to listen for all 162 * user/client domain deregistrations and timeouts. 163 * @param anUnlistenEventListener {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 164 * to listen for all user/client domain deregistrations and timeouts. 165 * @param anUnlistenScope scope of the unlisten events to receive 166 * @param aCallback callback 167 */ 168 public void addUnlistenListener(UnlistenEventListener.Scope anUnlistenScope, UnlistenEventListener anUnlistenEventListener, AsyncCallback<Void> aCallback) { 169 addUnlistenListener(anUnlistenScope, anUnlistenEventListener, null, aCallback); 170 } 171 172 /** 173 * Registers an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} to listen for all 174 * user/client domain deregistrations and timeouts. The custom {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} 175 * will be registered at the server side and transferred to all users/clients which have an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 176 * registered. That {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} can for example contain user information 177 * of your specific user-system to recover the user in your user-system on a timeout. The scope for unlisten events to receive is set to 178 * {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener.Scope#UNLISTEN} by default. 179 * To use other scopes see 180 * {@link de.novanic.eventservice.client.event.RemoteEventService#addUnlistenListener(de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener.Scope, de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener, de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent, com.google.gwt.user.client.rpc.AsyncCallback)}. 181 * @param anUnlistenEventListener {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 182 * to listen for all user/client domain deregistrations and timeouts. 183 * @param anUnlistenEvent {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} which can contain custom data 184 * @param aCallback callback 185 */ 186 public void addUnlistenListener(final UnlistenEventListener anUnlistenEventListener, UnlistenEvent anUnlistenEvent, AsyncCallback<Void> aCallback) { 187 addUnlistenListener(UnlistenEventListener.Scope.UNLISTEN, anUnlistenEventListener, anUnlistenEvent, aCallback); 188 } 189 190 /** 191 * Registers an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} to listen for all 192 * user/client domain deregistrations and timeouts. The custom {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} 193 * will be registered at the server side and transferred to all users/clients which have an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 194 * registered. That {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} can for example contain user information 195 * of your specific user-system to recover the user in your user-system on a timeout. 196 * @param anUnlistenScope scope of the unlisten events to receive 197 * @param anUnlistenEventListener {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} 198 * to listen for all user/client domain deregistrations and timeouts. 199 * @param anUnlistenEvent {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} which can contain custom data 200 * @param aCallback callback 201 */ 202 public void addUnlistenListener(final UnlistenEventListener.Scope anUnlistenScope, UnlistenEventListener anUnlistenEventListener, final UnlistenEvent anUnlistenEvent, final AsyncCallback<Void> aCallback) { 203 if(UnlistenEventListener.Scope.LOCAL == anUnlistenScope) { 204 addListenerLocal(DomainFactory.UNLISTEN_DOMAIN, anUnlistenEventListener); 205 schedule(new RegistrationUnlistenEventCommand(anUnlistenScope, getRemoteEventConnector(), anUnlistenEvent, aCallback)); 206 } else { 207 addListener(DomainFactory.UNLISTEN_DOMAIN, anUnlistenEventListener, new AsyncCallbackWrapper<Void>(aCallback) { 208 public void onSuccess(Void aResult) { 209 schedule(new RegistrationUnlistenEventCommand(anUnlistenScope, getRemoteEventConnector(), anUnlistenEvent, getCallback())); 210 } 211 }); 212 } 213 } 214 215 /** 216 * Removes a listener for a domain. 217 * The RemoteEventService will get inactive, when no other listeners are registered. 218 * @param aDomain domain 219 * @param aRemoteListener listener to remove 220 */ 221 public void removeListener(Domain aDomain, RemoteEventListener aRemoteListener) { 222 removeListener(aDomain, aRemoteListener, new VoidAsyncCallback()); 223 } 224 225 /** 226 * Removes a listener for a domain. 227 * The RemoteEventService will get inactive, when no other listeners are registered. 228 * @param aDomain domain to remove the listener from (the domain will be removed when no other listeners are registered to the domain) 229 * @param aRemoteListener listener to remove 230 * @param aCallback callback 231 */ 232 public void removeListener(Domain aDomain, RemoteEventListener aRemoteListener, AsyncCallback<Void> aCallback) { 233 if(aRemoteListener != null && myDomainListenerMapping.containsKey(aDomain)) { 234 //remove the listener 235 List<RemoteEventListener> theListeners = myDomainListenerMapping.get(aDomain); 236 if(theListeners != null) { 237 theListeners = removeOnCopy(theListeners, aRemoteListener); 238 myDomainListenerMapping.put(aDomain, theListeners); 239 } 240 //When it was the last listener, the domain will be deregistered for listening, because there aren't any listeners registered for the domain. 241 if(theListeners == null || theListeners.isEmpty()) { 242 removeDomain(aDomain, aCallback); 243 } 244 } 245 } 246 247 /** 248 * Registers the domain for listening and activates the RemoteEventService (starts listening) if it is inactive. 249 * @param aDomain domain to register/activate 250 * @param aCallback callback 251 */ 252 private void activate(Domain aDomain, AsyncCallback<Void> aCallback) { 253 activate(aDomain, null, aCallback); 254 } 255 256 /** 257 * Registers the domain with the EventFilter for listening and activates the RemoteEventService (starts listening) 258 * if it is inactive. 259 * @param aDomain domain to register/activate 260 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 261 * @param aCallback callback 262 */ 263 private void activate(Domain aDomain, EventFilter anEventFilter, AsyncCallback<Void> aCallback) { 264 schedule(new ActivationCommand(getRemoteEventConnector(), aDomain, anEventFilter, new ListenerEventNotification(), aCallback)); 265 } 266 267 /** 268 * Registers an EventFilter for a domain. This can be used when a listener is already added and an EventFilter 269 * needed later or isn't available when the listener is added. 270 * @param aDomain domain 271 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 272 */ 273 public void registerEventFilter(Domain aDomain, EventFilter anEventFilter) { 274 registerEventFilter(aDomain, anEventFilter, new VoidAsyncCallback()); 275 } 276 277 /** 278 * Registers an EventFilter for a domain. This can be used when a listener is already added and an EventFilter 279 * needed later or isn't available when the listener is added. 280 * @param aDomain domain 281 * @param anEventFilter EventFilter to filter the events before RemoteEventListener 282 * @param aCallback callback 283 */ 284 public void registerEventFilter(Domain aDomain, EventFilter anEventFilter, AsyncCallback<Void> aCallback) { 285 schedule(new RegistrationEventFilterCommand(getRemoteEventConnector(), aDomain, anEventFilter, aCallback)); 286 } 287 288 /** 289 * Deregisters the EventFilter for a domain. 290 * @param aDomain domain to remove the EventFilter from 291 */ 292 public void deregisterEventFilter(Domain aDomain) { 293 deregisterEventFilter(aDomain, new VoidAsyncCallback()); 294 } 295 296 /** 297 * Deregisters the EventFilter for a domain. 298 * @param aDomain domain to remove the EventFilter from 299 * @param aCallback callback 300 */ 301 public void deregisterEventFilter(Domain aDomain, AsyncCallback<Void> aCallback) { 302 schedule(new DeregistrationEventFilterCommand(getRemoteEventConnector(), aDomain, aCallback)); 303 } 304 305 /** 306 * Checks if the RemoteEventService is active (listening). 307 * @return true when active/listening, otherwise false 308 */ 309 public boolean isActive() { 310 return isListenActive(); 311 } 312 313 /** 314 * Returns all active domains (all domains where the client has listeners registered). 315 * @return all active domains 316 */ 317 public Set<Domain> getActiveDomains() { 318 return myDomainListenerMapping.keySet(); 319 } 320 321 /** 322 * Returns all registered listeners of a domain. 323 * @param aDomain domain 324 * @return all registered listeners of the domain 325 */ 326 public List<RemoteEventListener> getRegisteredListeners(Domain aDomain) { 327 return myDomainListenerMapping.get(aDomain); 328 } 329 330 /** 331 * Removes all RemoteEventListeners and deactivates the RemoteEventService (stop listening). 332 */ 333 public void removeListeners() { 334 removeListeners(new VoidAsyncCallback()); 335 } 336 337 /** 338 * Removes all RemoteEventListeners and deactivates the RemoteEventService (stop listening). 339 * @param aCallback callback (only called when a listener is registered for the domain) 340 */ 341 public void removeListeners(AsyncCallback<Void> aCallback) { 342 removeListeners(myDomainListenerMapping.keySet(), aCallback); 343 } 344 345 /** 346 * Calls unlisten for a set of domains (stop listening for these domains). The RemoteEventListeners for these 347 * domains will also be removed. 348 * {@link DefaultRemoteEventService#removeListeners()} can be used to call unlisten for all domains. 349 * @param aDomains domains to unlisten 350 */ 351 public void removeListeners(Set<Domain> aDomains) { 352 removeListeners(aDomains, new VoidAsyncCallback()); 353 } 354 355 /** 356 * Calls unlisten for a set of domains (stop listening for these domains). The RemoteEventListeners for these 357 * domains will also be removed. 358 * {@link DefaultRemoteEventService#removeListeners()} can be used to call unlisten for all domains. 359 * @param aDomains domains to unlisten 360 * @param aCallback callback (only called when a listener is registered for the domain) 361 */ 362 public void removeListeners(Set<Domain> aDomains, AsyncCallback<Void> aCallback) { 363 removeDomains(aDomains, aCallback); 364 } 365 366 /** 367 * Stops listening for the corresponding domain. The RemoteEventFilters for the domain will also be removed. 368 * {@link DefaultRemoteEventService#removeListeners()} can be used to call unlisten for all domains. 369 * @param aDomain domain to unlisten 370 */ 371 public void removeListeners(Domain aDomain) { 372 removeListeners(aDomain, new VoidAsyncCallback()); 373 } 374 375 /** 376 * Stops listening for the corresponding domain. The RemoteEventFilters for the domain will also be removed. 377 * {@link DefaultRemoteEventService#removeListeners()} can be used to call unlisten for all domains. 378 * @param aDomain domain to unlisten 379 * @param aCallback callback (only called when a listener is registered for the domain) 380 */ 381 public void removeListeners(Domain aDomain, AsyncCallback<Void> aCallback) { 382 unlisten(aDomain, aCallback); 383 } 384 385 /** 386 * Removes an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener}. 387 * The RemoteEventService will get inactive, when no other listeners are registered. 388 * @param anUnlistenEventListener {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} to remove 389 * @param aCallback callback 390 */ 391 public void removeUnlistenListener(UnlistenEventListener anUnlistenEventListener, AsyncCallback<Void> aCallback) { 392 removeListener(DomainFactory.UNLISTEN_DOMAIN, anUnlistenEventListener, aCallback); 393 } 394 395 /** 396 * Stops listening for {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEvent} instances. 397 * @param aCallback callback (only called when an {@link de.novanic.eventservice.client.event.listener.unlisten.UnlistenEventListener} is registered) 398 */ 399 public void removeUnlistenListeners(AsyncCallback<Void> aCallback) { 400 unlisten(DomainFactory.UNLISTEN_DOMAIN, aCallback); 401 } 402 403 /** 404 * Adds / sends an event to a domain. The event will be received from all clients which are registered to that domain. 405 * User-specific events can be added with the usage of this domain: {@link de.novanic.eventservice.client.event.domain.DomainFactory#USER_SPECIFIC_DOMAIN}. 406 * @param aDomain domain 407 * @param anEvent event 408 */ 409 public void addEvent(Domain aDomain, Event anEvent) { 410 addEvent(aDomain, anEvent, new VoidAsyncCallback()); 411 } 412 413 /** 414 * Adds / sends an event to a domain. The event will be received from all clients which are registered to that domain. 415 * User-specific events can be added with the usage of this domain: {@link de.novanic.eventservice.client.event.domain.DomainFactory#USER_SPECIFIC_DOMAIN}. 416 * @param aDomain domain 417 * @param anEvent event 418 * @param aCallback callback 419 */ 420 public void addEvent(Domain aDomain, Event anEvent, AsyncCallback<Void> aCallback) { 421 schedule(new EventExecutionCommand(getRemoteEventConnector(), aDomain, anEvent, aCallback)); 422 } 423 424 /** 425 * Stops listening for the corresponding domain. The RemoteEventFilters for the domain will also be removed. 426 * {@link DefaultRemoteEventService#removeListeners()} can be used to call unlisten for all domains. 427 * @param aDomain domain to unlisten 428 * @param aCallback callback (if it is NULL, no call is executed to the server) 429 * @return true when listeners registered (remote call needed), otherwise false 430 */ 431 private boolean unlisten(Domain aDomain, AsyncCallback<Void> aCallback) { 432 return removeDomain(aDomain, aCallback); 433 } 434 435 /** 436 * Removes the domain with all listener registrations to the domain. 437 * @param aDomain domain to remove 438 * @param aCallback callback (only called when the domain isn't already removed) 439 * @return true when the domain was removed, otherwise false (false when the domain was already removed) 440 */ 441 private boolean removeDomain(Domain aDomain, AsyncCallback<Void> aCallback) { 442 //remove the domain (all domain registrations) 443 boolean isRemoved = (myDomainListenerMapping.remove(aDomain) != null); 444 if(isRemoved) { 445 schedule(new DeactivationCommand(getRemoteEventConnector(), aDomain, aCallback)); 446 if(myDomainListenerMapping.isEmpty()) { 447 reset(); 448 } 449 } 450 return isRemoved; 451 } 452 453 /** 454 * Removes the domains with all listener registrations to the domains. 455 * @param aDomains domains to remove 456 * @param aCallback callback (only called when at least one of the domains isn't already removed) 457 * @return true when at least one domain was removed, otherwise false (false when all domains were already removed) 458 */ 459 private boolean removeDomains(Set<Domain> aDomains, AsyncCallback<Void> aCallback) { 460 //remove the domains (all domain registrations) 461 Set<Domain> theRemovableDomains = new HashSet<Domain>(aDomains); 462 Iterator<Domain> theDomainIterator = theRemovableDomains.iterator(); 463 while(theDomainIterator.hasNext()) { 464 Domain theDomain = theDomainIterator.next(); 465 if(myDomainListenerMapping.remove(theDomain) == null) { 466 theDomainIterator.remove(); 467 } 468 } 469 boolean isRemoved = !theRemovableDomains.isEmpty(); 470 if(isRemoved) { 471 schedule(new DeactivationCommand(getRemoteEventConnector(), theRemovableDomains, aCallback)); 472 if(myDomainListenerMapping.isEmpty()) { 473 reset(); 474 } 475 } 476 return isRemoved; 477 } 478 479 /** 480 * Adds an entry to a list and avoids {@link ConcurrentModificationException} when an entry is added while iterating. 481 * @param aList list to add an entry to 482 * @param anEntry entry to add 483 * @param <CT> type of the contained objects 484 * @return new list instance with the added entry 485 */ 486 private static <CT> List<CT> addOnCopy(List<CT> aList, CT anEntry) { 487 List<CT> theCollectionCopy = new ArrayList<CT>(aList); 488 if(theCollectionCopy.add(anEntry)) { 489 return theCollectionCopy; 490 } 491 return aList; 492 } 493 494 /** 495 * Removes an entry from a list and avoids {@link ConcurrentModificationException} when an entry is removed while iterating. 496 * @param aList list to remove an entry from 497 * @param anEntry entry to remove 498 * @param <CT> type of the contained objects 499 * @return new list instance without the removed entry 500 */ 501 private static <CT> List<CT> removeOnCopy(List<CT> aList, CT anEntry) { 502 List<CT> theCollectionCopy = new ArrayList<CT>(aList); 503 if(theCollectionCopy.remove(anEntry)) { 504 return theCollectionCopy; 505 } 506 return aList; 507 } 508 509 /** 510 * The ListenEventCallback is used to produce the listen cycle. It is attached as callback for the listen server call. 511 */ 512 private final class ListenerEventNotification implements EventNotification 513 { 514 /** 515 * That method will be called when a new event is arriving. 516 * @param aDomainEvent incoming event 517 */ 518 public void onNotify(DomainEvent aDomainEvent) { 519 //all listeners for the domain of the event will be executed 520 List<RemoteEventListener> theListeners = myDomainListenerMapping.get(aDomainEvent.getDomain()); 521 if(theListeners != null) { 522 final Event theEvent = aDomainEvent.getEvent(); 523 for(RemoteEventListener theListener: theListeners) { 524 theListener.apply(theEvent); 525 } 526 } 527 } 528 529 /** 530 * That method will be called when the listening for events is aborted (unexpected). 531 */ 532 public void onAbort() { 533 //if the remote doesn't know the client, all listeners will be removed and the connection gets inactive 534 removeListeners(); 535 } 536 } 537}