/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.course.assessment.manager; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.FlushModeType; import javax.persistence.TypedQuery; import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.coordinate.SyncerExecutor; import org.olat.core.util.resource.OresHelper; import org.olat.course.assessment.UserCourseInformations; import org.olat.course.assessment.model.UserCourseInfosImpl; import org.olat.repository.RepositoryEntry; import org.olat.resource.OLATResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; /** * Manager for infos as initial launch date... * * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ @Service("userCourseInformationsManager") public class UserCourseInformationsManagerImpl implements UserCourseInformationsManager { private static final OLog log = Tracing.createLoggerFor(UserCourseInformationsManagerImpl.class); @Autowired private DB dbInstance; @Override public UserCourseInfosImpl getUserCourseInformations(OLATResource resource, IdentityRef identity) { try { StringBuilder sb = new StringBuilder(); sb.append("select infos from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join fetch infos.resource as resource") .append(" inner join infos.identity as identity") .append(" where identity.key=:identityKey and resource.key=:resKey and resource.resName='CourseModule'"); List<UserCourseInfosImpl> infoList = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), UserCourseInfosImpl.class) .setParameter("identityKey", identity.getKey()) .setParameter("resKey", resource.getKey()) .getResultList(); if(infoList.isEmpty()) { return null; } return infoList.get(0); } catch (Exception e) { log.error("Cannot retrieve course informations for: " + identity + " from " + identity, e); return null; } } @Override public List<UserCourseInformations> getUserCourseInformations(IdentityRef identity, List<OLATResource> resources) { if(resources == null || resources.isEmpty()) { return Collections.emptyList(); } try { StringBuilder sb = new StringBuilder(); sb.append("select infos from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join fetch infos.resource as resource") .append(" inner join infos.identity as identity") .append(" where identity.key=:identityKey and resource.key in (:resKeys)"); List<Long> resourceKeys = PersistenceHelper.toKeys(resources); TypedQuery<UserCourseInformations> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), UserCourseInformations.class) .setParameter("identityKey", identity.getKey()) .setParameter("resKeys", resourceKeys); List<UserCourseInformations> infoList = query.getResultList(); return infoList; } catch (Exception e) { log.error("Cannot retrieve course informations for: " + identity + " from " + identity, e); return null; } } /** * Execute the update statement * @param courseResource * @param identity * @return */ protected int lowLevelUpdate(OLATResource courseResource, Identity identity) { return dbInstance.getCurrentEntityManager().createNamedQuery("updateLaunchDates") .setParameter("identityKey", identity.getKey()) .setParameter("resourceKey", courseResource.getKey()) .setParameter("now", new Date()) .executeUpdate(); } /** * Update (or create if not exists) the course informations for a user * @param userCourseEnv * @return */ @Override public void updateUserCourseInformations(final OLATResource courseResource, final Identity identity) { int updatedRows = lowLevelUpdate(courseResource, identity); dbInstance.commit();//to make it quick if(updatedRows == 0) { OLATResourceable lockRes = OresHelper.createOLATResourceableInstance("CourseLaunchDate::Identity", identity.getKey()); CoordinatorManager.getInstance().getCoordinator().getSyncer().doInSync(lockRes, new SyncerExecutor(){ @Override public void execute() { try { int retryUpdatedRows = lowLevelUpdate(courseResource, identity); if(retryUpdatedRows == 0) { UserCourseInfosImpl infos = new UserCourseInfosImpl(); infos.setIdentity(identity); infos.setCreationDate(new Date()); infos.setInitialLaunch(new Date()); infos.setLastModified(new Date()); infos.setRecentLaunch(new Date()); infos.setVisit(1); infos.setResource(courseResource); dbInstance.getCurrentEntityManager().persist(infos); } } catch (Exception e) { log.error("Cannot update course informations for: " + identity + " from " + identity, e); } } }); } } @Override public Date getRecentLaunchDate(OLATResource resource, IdentityRef identity) { StringBuilder sb = new StringBuilder(); sb.append("select infos.recentLaunch from usercourseinfos as infos ") .append(" inner join infos.resource as resource") .append(" where infos.identity.key=:identityKey and resource.key=:resKey and resource.resName='CourseModule'"); List<Date> infoList = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Date.class) .setParameter("identityKey", identity.getKey()) .setParameter("resKey", resource.getKey()) .getResultList(); if(infoList.isEmpty()) { return null; } return infoList.get(0); } @Override public Date getInitialLaunchDate(OLATResource resource, IdentityRef identity) { return getInitialLaunchDate(resource, identity.getKey()); } public Date getInitialLaunchDate(OLATResource resource, Long identityKey) { try { StringBuilder sb = new StringBuilder(); sb.append("select infos.initialLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join infos.resource as resource") .append(" where infos.identity.key=:identityKey and resource.key=:resKey and resource.resName='CourseModule'"); List<Date> infoList = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Date.class) .setParameter("identityKey", identityKey) .setParameter("resKey", resource.getKey()) .getResultList(); if(infoList.isEmpty()) { return null; } return infoList.get(0); } catch (Exception e) { log.error("Cannot retrieve course informations for: " + resource.getResourceableId(), e); return null; } } /** * Return a map of identity keys to initial launch date. * @param courseEnv * @param identities * @return */ @Override public Map<Long,Date> getInitialLaunchDates(OLATResource resource, List<Identity> identities) { if(identities == null || identities.isEmpty()) { return new HashMap<Long,Date>(); } try { List<Long> identityKeys = PersistenceHelper.toKeys(identities); StringBuilder sb = new StringBuilder(); sb.append("select infos.identity.key, infos.initialLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join infos.resource as resource") .append(" where resource.key=:resKey and resource.resName='CourseModule'"); Set<Long> identityKeySet = null; if(identityKeys.size() < 100) { sb.append(" and infos.identity.key in (:identityKeys)"); identityKeySet = new HashSet<Long>(identityKeys); } TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Object[].class) .setParameter("resKey", resource.getKey()); if(identityKeys.size() < 100) { query.setParameter("identityKeys", identityKeys); } List<Object[]> infoList = query.getResultList(); Map<Long,Date> dateMap = new HashMap<Long,Date>(); for(Object[] infos:infoList) { Long identityKey = (Long)infos[0]; if(identityKeySet == null || identityKeySet.contains(identityKey)) { Date initialLaunch = (Date)infos[1]; dateMap.put(identityKey, initialLaunch); } } return dateMap; } catch (Exception e) { log.error("Cannot retrieve course informations for: " + resource.getResourceableId(), e); return Collections.emptyMap(); } } /** * Return a map of identity keys to initial launch date. * * @param courseResourceId The course resourceable id * @return */ @Override public Map<Long,Date> getInitialLaunchDates(Long courseResourceId) { try { StringBuilder sb = new StringBuilder(); sb.append("select infos.identity.key, infos.initialLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join infos.resource as resource") .append(" where resource.resId=:resId and resource.resName='CourseModule'"); TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Object[].class) .setParameter("resId", courseResourceId); List<Object[]> infoList = query.getResultList(); Map<Long,Date> dateMap = new HashMap<Long,Date>(); for(Object[] infos:infoList) { Long identityKey = (Long)infos[0]; Date initialLaunch = (Date)infos[1]; if(identityKey != null && initialLaunch != null) { dateMap.put(identityKey, initialLaunch); } } return dateMap; } catch (Exception e) { log.error("Cannot retrieve course informations for: " + courseResourceId, e); return Collections.emptyMap(); } } @Override public Map<Long, Date> getRecentLaunchDates(OLATResource resource) { try { StringBuilder sb = new StringBuilder(); sb.append("select infos.identity.key, infos.recentLaunch from usercourseinfos as infos where infos.resource.key=:resKey"); List<Object[]> infoList = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Object[].class) .setParameter("resKey", resource.getKey()) .getResultList(); Map<Long, Date> dateMap = new HashMap<>(); for(Object[] infos:infoList) { Long identityKey = (Long)infos[0]; Date recentLaunch = (Date)infos[1]; dateMap.put(identityKey, recentLaunch); } return dateMap; } catch (Exception e) { log.error("Cannot retrieve course informations for: " + resource.getResourceableId(), e); return Collections.emptyMap(); } } /** * Return a map of identity keys to initial launch date. * @param courseEnv * @return */ @Override public Map<Long,Date> getRecentLaunchDates(OLATResource resource, List<Identity> identities) { if(identities == null || identities.isEmpty()) { return new HashMap<Long,Date>(); } try { List<Long> identityKeys = PersistenceHelper.toKeys(identities); StringBuilder sb = new StringBuilder(); sb.append("select infos.identity.key, infos.recentLaunch from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" inner join infos.resource as resource") .append(" where resource.key=:resKey and resource.resName='CourseModule'"); Set<Long> identityKeySet = null; if(identityKeys.size() < 100) { sb.append(" and infos.identity.key in (:identityKeys)"); identityKeySet = new HashSet<Long>(identityKeys); } TypedQuery<Object[]> query = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Object[].class) .setParameter("resKey", resource.getKey()); if(identityKeys.size() < 100) { query.setParameter("identityKeys", identityKeys); } List<Object[]> infoList = query.getResultList(); Map<Long,Date> dateMap = new HashMap<Long,Date>(); for(Object[] infos:infoList) { Long identityKey = (Long)infos[0]; if(identityKeySet == null || identityKeySet.contains(identityKey)) { Date initialLaunch = (Date)infos[1]; dateMap.put(identityKey, initialLaunch); } } return dateMap; } catch (Exception e) { log.error("Cannot retrieve course informations for: " + resource.getResourceableId(), e); return Collections.emptyMap(); } } @Override public int deleteUserCourseInformations(RepositoryEntry entry) { try { StringBuilder sb = new StringBuilder(); sb.append("delete from ").append(UserCourseInfosImpl.class.getName()).append(" as infos ") .append(" where resource.key=:resourceKey"); int count = dbInstance.getCurrentEntityManager() .createQuery(sb.toString()) .setParameter("resourceKey", entry.getOlatResource().getKey()) .setFlushMode(FlushModeType.AUTO) .executeUpdate(); return count; } catch (Exception e) { log.error("Cannot Delete course informations for: " + entry, e); return -1; } } }