SEBSERV-163 back-end and fixed tests
This commit is contained in:
		
							parent
							
								
									cea166f065
								
							
						
					
					
						commit
						65b81af1eb
					
				
					 5 changed files with 97 additions and 7 deletions
				
			
		|  | @ -9,8 +9,10 @@ | ||||||
| package ch.ethz.seb.sebserver.gbl.model.session; | package ch.ethz.seb.sebserver.gbl.model.session; | ||||||
| 
 | 
 | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
|  | import java.util.HashSet; | ||||||
| import java.util.Iterator; | import java.util.Iterator; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  | import java.util.Set; | ||||||
| 
 | 
 | ||||||
| import com.fasterxml.jackson.annotation.JsonCreator; | import com.fasterxml.jackson.annotation.JsonCreator; | ||||||
| import com.fasterxml.jackson.annotation.JsonIgnore; | import com.fasterxml.jackson.annotation.JsonIgnore; | ||||||
|  | @ -20,6 +22,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.GrantEntity; | import ch.ethz.seb.sebserver.gbl.model.GrantEntity; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; | import ch.ethz.seb.sebserver.gbl.model.exam.Indicator; | ||||||
| import ch.ethz.seb.sebserver.gbl.monitoring.IndicatorValue; | import ch.ethz.seb.sebserver.gbl.monitoring.IndicatorValue; | ||||||
| import ch.ethz.seb.sebserver.gbl.monitoring.SimpleIndicatorValue; | import ch.ethz.seb.sebserver.gbl.monitoring.SimpleIndicatorValue; | ||||||
|  | @ -41,6 +44,8 @@ public class ClientConnectionData implements GrantEntity { | ||||||
|     public final Boolean missingPing; |     public final Boolean missingPing; | ||||||
|     public final Boolean pendingNotification; |     public final Boolean pendingNotification; | ||||||
| 
 | 
 | ||||||
|  |     private Set<Long> groups = null; | ||||||
|  | 
 | ||||||
|     @JsonCreator |     @JsonCreator | ||||||
|     public ClientConnectionData( |     public ClientConnectionData( | ||||||
|             @JsonProperty(ATTR_MISSING_PING) final Boolean missingPing, |             @JsonProperty(ATTR_MISSING_PING) final Boolean missingPing, | ||||||
|  | @ -64,6 +69,19 @@ public class ClientConnectionData implements GrantEntity { | ||||||
|         this.indicatorValues = Utils.immutableListOf(indicatorValues); |         this.indicatorValues = Utils.immutableListOf(indicatorValues); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     public void addToClientGroup(final ClientGroup group) { | ||||||
|  |         if (this.groups == null) { | ||||||
|  |             this.groups = new HashSet<>(1); | ||||||
|  |         } | ||||||
|  |         this.groups.add(group.id); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonIgnore | ||||||
|  |     public boolean isInClientGroup(final Long clientGroupId) { | ||||||
|  |         return this.groups != null && this.groups.contains(clientGroupId); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public EntityType entityType() { |     public EntityType entityType() { | ||||||
|         return this.clientConnection.entityType(); |         return this.clientConnection.entityType(); | ||||||
|  |  | ||||||
|  | @ -10,6 +10,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.dao; | ||||||
| 
 | 
 | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| 
 | 
 | ||||||
|  | import org.springframework.cache.annotation.CacheEvict; | ||||||
|  | import org.springframework.cache.annotation.Cacheable; | ||||||
|  | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; | import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO; | ||||||
|  | @ -17,10 +20,24 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSuppor | ||||||
| /** Concrete EntityDAO interface of ClientGroup entities */ | /** Concrete EntityDAO interface of ClientGroup entities */ | ||||||
| public interface ClientGroupDAO extends EntityDAO<ClientGroup, ClientGroup>, BulkActionSupportDAO<ClientGroup> { | public interface ClientGroupDAO extends EntityDAO<ClientGroup, ClientGroup>, BulkActionSupportDAO<ClientGroup> { | ||||||
| 
 | 
 | ||||||
|  |     public static final String CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE = "RUNNING_EXAM_CLIENT_GROUP_CACHE"; | ||||||
|  | 
 | ||||||
|     /** Get a collection of all ClientGroup entities for a specified exam. |     /** Get a collection of all ClientGroup entities for a specified exam. | ||||||
|      * |      * | ||||||
|      * @param examId the Exam identifier to get the ClientGroups for |      * @param examId the Exam identifier to get the ClientGroups for | ||||||
|      * @return Result referring to the collection of ClientGroups of an Exam or to an error if happened */ |      * @return Result referring to the collection of ClientGroups of an Exam or to an error if happened */ | ||||||
|  |     @Cacheable( | ||||||
|  |             cacheNames = CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE, | ||||||
|  |             key = "#examId", | ||||||
|  |             condition = "#examId!=null", | ||||||
|  |             unless = "#result.hasError()") | ||||||
|     Result<Collection<ClientGroup>> allForExam(Long examId); |     Result<Collection<ClientGroup>> allForExam(Long examId); | ||||||
| 
 | 
 | ||||||
|  |     @CacheEvict( | ||||||
|  |             cacheNames = CACHE_NAME_RUNNING_EXAM_CLIENT_GROUP_CACHE, | ||||||
|  |             key = "#examId") | ||||||
|  |     default void evictCacheForExam(final Long examId) { | ||||||
|  |         // just evict the cache | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Result; | import ch.ethz.seb.sebserver.gbl.util.Result; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientGroupDAO; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO; | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.RemoteProctoringRoomDAO; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService; | import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigService; | ||||||
|  | @ -45,6 +46,7 @@ public class ExamSessionCacheService { | ||||||
|     private static final Logger log = LoggerFactory.getLogger(ExamSessionCacheService.class); |     private static final Logger log = LoggerFactory.getLogger(ExamSessionCacheService.class); | ||||||
| 
 | 
 | ||||||
|     private final ExamDAO examDAO; |     private final ExamDAO examDAO; | ||||||
|  |     private final ClientGroupDAO clientGroupDAO; | ||||||
|     private final ClientConnectionDAO clientConnectionDAO; |     private final ClientConnectionDAO clientConnectionDAO; | ||||||
|     private final InternalClientConnectionDataFactory internalClientConnectionDataFactory; |     private final InternalClientConnectionDataFactory internalClientConnectionDataFactory; | ||||||
|     private final ExamConfigService sebExamConfigService; |     private final ExamConfigService sebExamConfigService; | ||||||
|  | @ -52,6 +54,7 @@ public class ExamSessionCacheService { | ||||||
| 
 | 
 | ||||||
|     protected ExamSessionCacheService( |     protected ExamSessionCacheService( | ||||||
|             final ExamDAO examDAO, |             final ExamDAO examDAO, | ||||||
|  |             final ClientGroupDAO clientGroupDAO, | ||||||
|             final ClientConnectionDAO clientConnectionDAO, |             final ClientConnectionDAO clientConnectionDAO, | ||||||
|             final InternalClientConnectionDataFactory internalClientConnectionDataFactory, |             final InternalClientConnectionDataFactory internalClientConnectionDataFactory, | ||||||
|             final ExamConfigService sebExamConfigService, |             final ExamConfigService sebExamConfigService, | ||||||
|  | @ -59,6 +62,7 @@ public class ExamSessionCacheService { | ||||||
|             final RemoteProctoringRoomDAO remoteProctoringRoomDAO) { |             final RemoteProctoringRoomDAO remoteProctoringRoomDAO) { | ||||||
| 
 | 
 | ||||||
|         this.examDAO = examDAO; |         this.examDAO = examDAO; | ||||||
|  |         this.clientGroupDAO = clientGroupDAO; | ||||||
|         this.clientConnectionDAO = clientConnectionDAO; |         this.clientConnectionDAO = clientConnectionDAO; | ||||||
|         this.internalClientConnectionDataFactory = internalClientConnectionDataFactory; |         this.internalClientConnectionDataFactory = internalClientConnectionDataFactory; | ||||||
|         this.sebExamConfigService = sebExamConfigService; |         this.sebExamConfigService = sebExamConfigService; | ||||||
|  | @ -98,6 +102,7 @@ public class ExamSessionCacheService { | ||||||
|             log.trace("Conditional eviction of running Exam from cache: {}", isRunning(exam)); |             log.trace("Conditional eviction of running Exam from cache: {}", isRunning(exam)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.clientGroupDAO.evictCacheForExam(exam.id); | ||||||
|         return exam; |         return exam; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -110,6 +115,7 @@ public class ExamSessionCacheService { | ||||||
|             log.trace("Conditional eviction of running Exam from cache: {}", examId); |             log.trace("Conditional eviction of running Exam from cache: {}", examId); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         this.clientGroupDAO.evictCacheForExam(examId); | ||||||
|         return examId; |         return examId; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -8,12 +8,20 @@ | ||||||
| 
 | 
 | ||||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; | package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; | ||||||
| 
 | 
 | ||||||
|  | import java.util.Collection; | ||||||
|  | import java.util.Collections; | ||||||
|  | 
 | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| 
 | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.exam.ClientGroup; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; | import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; | import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.monitoring.ClientGroupMatcherService; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||||
|  | import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientGroupDAO; | ||||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService; | import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificationService; | ||||||
| 
 | 
 | ||||||
| @Lazy | @Lazy | ||||||
|  | @ -21,34 +29,64 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientNotificati | ||||||
| @WebServiceProfile | @WebServiceProfile | ||||||
| public class InternalClientConnectionDataFactory { | public class InternalClientConnectionDataFactory { | ||||||
| 
 | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(InternalClientConnectionDataFactory.class); | ||||||
|  | 
 | ||||||
|     private final ClientIndicatorFactory clientIndicatorFactory; |     private final ClientIndicatorFactory clientIndicatorFactory; | ||||||
|     private final SEBClientNotificationService sebClientNotificationService; |     private final SEBClientNotificationService sebClientNotificationService; | ||||||
|  |     private final ClientGroupDAO clientGroupDAO; | ||||||
|  |     private final ClientGroupMatcherService clientGroupMatcherService; | ||||||
| 
 | 
 | ||||||
|     public InternalClientConnectionDataFactory( |     public InternalClientConnectionDataFactory( | ||||||
|             final ClientIndicatorFactory clientIndicatorFactory, |             final ClientIndicatorFactory clientIndicatorFactory, | ||||||
|             final SEBClientNotificationService sebClientNotificationService) { |             final SEBClientNotificationService sebClientNotificationService, | ||||||
|  |             final ClientGroupDAO clientGroupDAO, | ||||||
|  |             final ClientGroupMatcherService clientGroupMatcherService) { | ||||||
| 
 | 
 | ||||||
|         this.clientIndicatorFactory = clientIndicatorFactory; |         this.clientIndicatorFactory = clientIndicatorFactory; | ||||||
|         this.sebClientNotificationService = sebClientNotificationService; |         this.sebClientNotificationService = sebClientNotificationService; | ||||||
|  |         this.clientGroupDAO = clientGroupDAO; | ||||||
|  |         this.clientGroupMatcherService = clientGroupMatcherService; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public ClientConnectionDataInternal createClientConnectionData(final ClientConnection clientConnection) { |     public ClientConnectionDataInternal createClientConnectionData(final ClientConnection clientConnection) { | ||||||
| 
 | 
 | ||||||
|  |         ClientConnectionDataInternal result; | ||||||
|         if (clientConnection.status == ConnectionStatus.CLOSED |         if (clientConnection.status == ConnectionStatus.CLOSED | ||||||
|                 || clientConnection.status == ConnectionStatus.DISABLED) { |                 || clientConnection.status == ConnectionStatus.DISABLED) { | ||||||
| 
 | 
 | ||||||
|             // dispose notification indication for closed or disabled connection |             // dispose notification indication for closed or disabled connection | ||||||
|             return new ClientConnectionDataInternal( |             result = new ClientConnectionDataInternal( | ||||||
|                     clientConnection, |                     clientConnection, | ||||||
|                     () -> false, |                     () -> false, | ||||||
|                     this.clientIndicatorFactory.createFor(clientConnection)); |                     this.clientIndicatorFactory.createFor(clientConnection)); | ||||||
|  |         } else { | ||||||
|  | 
 | ||||||
|  |             result = new ClientConnectionDataInternal( | ||||||
|  |                     clientConnection, | ||||||
|  |                     () -> this.sebClientNotificationService | ||||||
|  |                             .hasAnyPendingNotification(clientConnection), | ||||||
|  |                     this.clientIndicatorFactory.createFor(clientConnection)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return new ClientConnectionDataInternal( |         // set client groups for connection | ||||||
|                 clientConnection, |         if (clientConnection.examId != null) { | ||||||
|                 () -> this.sebClientNotificationService |             final Collection<ClientGroup> clientGroups = this.clientGroupDAO | ||||||
|                         .hasAnyPendingNotification(clientConnection), |                     .allForExam(clientConnection.examId) | ||||||
|                 this.clientIndicatorFactory.createFor(clientConnection)); |                     .onError( | ||||||
|  |                             error -> log.error("Failed to get client groups for clientConnection: {}", clientConnection, | ||||||
|  |                                     error)) | ||||||
|  |                     .getOr(Collections.emptyList()); | ||||||
|  | 
 | ||||||
|  |             if (!clientGroups.isEmpty()) { | ||||||
|  |                 clientGroups.forEach(clientGroup -> { | ||||||
|  |                     if (this.clientGroupMatcherService.isInGroup(clientConnection, clientGroup)) { | ||||||
|  |                         result.addToClientGroup(clientGroup); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,17 @@ | ||||||
|         </resources> |         </resources> | ||||||
|     </cache> |     </cache> | ||||||
| 
 | 
 | ||||||
|  |     <cache alias="RUNNING_EXAM_CLIENT_GROUP_CACHE"> | ||||||
|  |         <key-type>java.lang.Long</key-type> | ||||||
|  |         <value-type>ch.ethz.seb.sebserver.gbl.util.Result</value-type> | ||||||
|  |         <expiry> | ||||||
|  |             <ttl unit="hours">24</ttl> | ||||||
|  |         </expiry> | ||||||
|  |         <resources> | ||||||
|  |             <heap unit="entries">10</heap> | ||||||
|  |         </resources> | ||||||
|  |     </cache> | ||||||
|  |      | ||||||
|     <cache alias="ACTIVE_CLIENT_CONNECTION"> |     <cache alias="ACTIVE_CLIENT_CONNECTION"> | ||||||
|         <key-type>java.lang.String</key-type> |         <key-type>java.lang.String</key-type> | ||||||
|         <value-type>ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ClientConnectionDataInternal</value-type> |         <value-type>ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.ClientConnectionDataInternal</value-type> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti