package com.griddynamics.jagger.dbapi.provider; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; import com.griddynamics.jagger.dbapi.DataSaverService; import com.griddynamics.jagger.dbapi.dto.SessionDataDto; import com.griddynamics.jagger.dbapi.dto.TagDto; import com.griddynamics.jagger.dbapi.entity.SessionData; import com.griddynamics.jagger.dbapi.entity.TagEntity; import com.griddynamics.jagger.dbapi.util.HTMLFormatter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.PersistenceException; import javax.persistence.Query; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** * Created by kgribov on 4/7/14. */ @SuppressWarnings("unchecked") @Component public class SessionInfoProviderImpl implements SessionInfoProvider { private static final Logger log = LoggerFactory.getLogger(SessionInfoProviderImpl.class); private EntityManager entityManager; private DataSaverService dataSaverService; private boolean isUserCommentStorageAvailable = false; private boolean isTagsStorageAvailable = false; public void setIsUserCommentStorageAvailable(Boolean isUserCommentStorageAvailable) { this.isUserCommentStorageAvailable = isUserCommentStorageAvailable; } public void setIsTagsStorageAvailable(Boolean isTagsStorageAvailable) { this.isTagsStorageAvailable = isTagsStorageAvailable; } @PersistenceContext public void setEntityManager(EntityManager entityManager) { this.entityManager = entityManager; } @Autowired public void setDataSaverService(DataSaverService dataSaverService) { this.dataSaverService = dataSaverService; } public List<TagDto> getAllTags() { List<TagDto> allTags = new ArrayList<>(); if (isTagsStorageAvailable) { List<TagEntity> tags = entityManager.createQuery("select te from TagEntity as te").getResultList(); if (!tags.isEmpty()) { allTags.addAll(tags.stream().map(tagEntity -> new TagDto(tagEntity.getName(), tagEntity.getDescription())) .collect(Collectors.toList())); } } return allTags; } public void saveTags(Long sessionDataId, List<TagDto> tags) { dataSaverService.saveTags(sessionDataId, tags); } public void saveUserComment(Long sessionDataId, String userComment) throws RuntimeException { dataSaverService.saveUserComment(sessionDataId, userComment); } public Long getTotalSize() { Long result; try { result = (Long) entityManager.createQuery("select count(sessionData.id) from SessionData as sessionData").getSingleResult(); } catch (PersistenceException ex) { Throwable rootCause = ExceptionUtils.getRootCause(ex); if (rootCause != null && StringUtils.contains(rootCause.getMessage(), "doesn't exist")) { result = 0L; } else { throw ex; } } return result; } public Long getTotalSizeByDate(Date from, Date to) { return (Long) entityManager.createQuery("select count(sd.id) from SessionData as sd where sd.startTime between :from and :to") .setParameter("from", from) .setParameter("to", to) .getSingleResult(); } public Long getTotalSizeByIds(Set<String> sessionIds) { return (Long) entityManager.createQuery("select count(sd.id) from SessionData as sd where sd.sessionId in (:sessionIds)") .setParameter("sessionIds", new ArrayList<>(sessionIds)) .getSingleResult(); } public Long getTotalSizeByTags(Set<String> sessionTagNames) { if (isTagsStorageAvailable) { return ((BigInteger) entityManager.createNativeQuery("SELECT count(DISTINCT ste.sessions_id) FROM SessionTagEntity AS ste WHERE ste" + ".tags_name IN (:sessionTagNames)") .setParameter("sessionTagNames", new ArrayList<>(sessionTagNames)) .getSingleResult()).longValue(); } else { return 0L; } } public Long getFirstPosition(Set<String> selectedIds) throws RuntimeException { if (selectedIds.isEmpty()) { return 0L; } List<Date> startTimeList = (List<Date>) entityManager.createQuery("select ses.startTime from SessionData ses where ses.sessionId in " + "(:sessionIds) order by ses.startTime asc") .setMaxResults(1) .setParameter("sessionIds", selectedIds).getResultList(); if (startTimeList.isEmpty()) { return 0L; } Date startTime = startTimeList.iterator().next(); Long lastPosition = (Long) entityManager.createQuery("select count(ses.id) from SessionData ses where startTime<=:startTime") .setParameter("startTime", startTime).getSingleResult(); return lastPosition - 1; } public List<SessionDataDto> getAll(int start, int length) { checkArgument(start >= 0, "start is negative"); checkArgument(length >= 0, "length is negative"); long timestamp = System.currentTimeMillis(); List<SessionDataDto> sessionDataDtoList; try { sessionDataDtoList = getAllWithMetaData(start, length); } catch (PersistenceException ex) { Throwable rootCause = ExceptionUtils.getRootCause(ex); if (rootCause != null && StringUtils.contains(rootCause.getMessage(), "doesn't exist")) { return Collections.emptyList(); } else { throw ex; } } catch (Exception e) { log.error("Exception occurred fetching session data.", e); throw new RuntimeException(e); } if (sessionDataDtoList.isEmpty()) { return Collections.emptyList(); } log.debug("There was loaded {} sessions data for {} ms", sessionDataDtoList.size(), System.currentTimeMillis() - timestamp); return sessionDataDtoList; } private List<SessionDataDto> getAllWithMetaData(int start, int length) { List<SessionData> sessionDataList = (List<SessionData>) entityManager.createQuery("select sd from SessionData as sd order by sd.startTime asc").setFirstResult(start).setMaxResults(length) .getResultList(); if (sessionDataList == null || sessionDataList.isEmpty()) { return Collections.emptyList(); } List<Long> sessionIds = sessionDataList.stream().map(SessionData::getId).collect(Collectors.toList()); Map<Long, String> userCommentMap = Collections.EMPTY_MAP; if (isUserCommentStorageAvailable) { List<Object[]> userComments = entityManager.createQuery( "select smd.sessionData.id, smd.userComment from SessionMetaDataEntity as smd where smd.sessionData in (:sessionDataList)") .setParameter("sessionDataList", sessionDataList) .getResultList(); if (!userComments.isEmpty()) { userCommentMap = new HashMap<>(userComments.size()); for (Object[] objects : userComments) { userCommentMap.put((Long) objects[0], (String) objects[1]); } } } Multimap<Long, TagDto> tagMap = HashMultimap.create(); if (isTagsStorageAvailable) { List<Object[]> sessionTags = entityManager.createNativeQuery("SELECT a.sessions_id, a.tags_name, te.description " + "FROM TagEntity AS te, (SELECT DISTINCT ste.sessions_id, ste.tags_name FROM SessionTagEntity AS ste WHERE ste.sessions_id IN " + "(:sessionIds)) AS a " + "WHERE a.tags_name=te.name") .setParameter("sessionIds", sessionIds) .getResultList(); for (Object[] tags : sessionTags) { Long sessionId = ((BigInteger) tags[0]).longValue(); tagMap.put(sessionId, new TagDto((String) tags[1], (String) tags[2])); } } List<SessionDataDto> sessionDataDtoList = new ArrayList<>(sessionDataList.size()); for (SessionData sessionData : sessionDataList) { sessionDataDtoList.add(createSessionDataDto(sessionData, userCommentMap.get(sessionData.getId()), new ArrayList<>(tagMap.get(sessionData.getId())))); } return sessionDataDtoList; } public List<SessionDataDto> getByDatePeriod(int start, int length, Date from, Date to) { checkArgument(start >= 0, "start is negative"); checkArgument(length >= 0, "length is negative"); checkNotNull(from, "from is null"); checkNotNull(to, "to is null"); long timestamp = System.currentTimeMillis(); List<SessionDataDto> sessionDataDtoList; try { List<SessionData> sessionDataList = (List<SessionData>) entityManager.createQuery("select sd from SessionData as sd where sd.startTime between :from and :to order by sd.startTime asc") .setParameter("from", from) .setParameter("to", to) .setFirstResult(start) .setMaxResults(length) .getResultList(); if (sessionDataList.isEmpty()) { return Collections.emptyList(); } List<Long> sessionIds = sessionDataList.stream().map(SessionData::getId).collect(Collectors.toList()); Map<Long, String> userCommentMap = Collections.emptyMap(); if (isUserCommentStorageAvailable) { List<Object[]> userComments = entityManager.createQuery( "select smd.sessionData.id, smd.userComment from SessionMetaDataEntity as smd where smd.sessionData in (:sessionDataList)") .setParameter("sessionDataList", sessionDataList) .getResultList(); if (!userComments.isEmpty()) { userCommentMap = new HashMap<>(userComments.size()); for (Object[] objects : userComments) { userCommentMap.put((Long) objects[0], (String) objects[1]); } } } Multimap<Long, TagDto> tagMap = HashMultimap.create(); if (isTagsStorageAvailable) { List<Object[]> sessionTags = entityManager.createNativeQuery("SELECT a.sessions_id, a.tags_name, te.description " + "FROM TagEntity AS te, (SELECT DISTINCT ste.sessions_id, ste.tags_name FROM SessionTagEntity AS ste WHERE ste.sessions_id " + "IN (:sessionIds)) AS a " + "WHERE a.tags_name=te.name") .setParameter("sessionIds", sessionIds) .getResultList(); for (Object[] tags : sessionTags) { Long sessionId = ((BigInteger) tags[0]).longValue(); tagMap.put(sessionId, new TagDto((String) tags[1], (String) tags[2])); } } sessionDataDtoList = new ArrayList<>(sessionDataList.size()); for (SessionData sessionData : sessionDataList) { sessionDataDtoList.add(createSessionDataDto(sessionData, userCommentMap.get(sessionData.getId()), new ArrayList<>(tagMap.get(sessionData.getId())))); } log.debug("There was loaded {} sessions data for {} ms", sessionDataDtoList.size(), System.currentTimeMillis() - timestamp); } catch (Exception e) { log.error("Error was occurred during session data between " + from + " to " + to + "; start " + start + ", length " + length, e); throw new RuntimeException(e); } return sessionDataDtoList; } public List<SessionDataDto> getBySessionIds(int start, int length, Set<String> sessionIds) { checkArgument(start >= 0, "start is negative"); checkArgument(length >= 0, "length is negative"); checkNotNull(sessionIds, "sessionIds is null"); boolean isFetchAll = sessionIds.size() == 0; // if input set is empty - fetch all session data. long timestamp = System.currentTimeMillis(); List<SessionDataDto> sessionDataDtoList; try { Query query = entityManager.createQuery( "select sd from SessionData as sd " + (isFetchAll ? " " : "where sd.sessionId in (:sessionIds) ") + "order by sd.startTime asc" ).setFirstResult(start); if (!isFetchAll) { query.setParameter("sessionIds", new ArrayList<>(sessionIds)) .setMaxResults(length); } List<SessionData> sessionDataList = (List<SessionData>) query.getResultList(); if (sessionDataList.isEmpty()) { return Collections.emptyList(); } Map<Long, String> userCommentMap = Collections.emptyMap(); if (isUserCommentStorageAvailable) { query = entityManager.createQuery( "select smd.sessionData.id, smd.userComment from SessionMetaDataEntity as smd " + (isFetchAll ? " " : " where smd.sessionData in (:sessionDataList)") ); if (!isFetchAll) { query.setParameter("sessionDataList", sessionDataList); } List<Object[]> userComments = query.getResultList(); if (!userComments.isEmpty()) { userCommentMap = new HashMap<>(userComments.size()); for (Object[] objects : userComments) { userCommentMap.put((Long) objects[0], (String) objects[1]); } } } Multimap<Long, TagDto> tagMap = HashMultimap.create(); if (isTagsStorageAvailable) { query = entityManager.createNativeQuery( "select a.sessions_id, a.tags_name, te.description " + "from TagEntity as te, " + " (" + "select distinct ste.sessions_id, ste.tags_name " + "from SessionTagEntity as ste " + (isFetchAll ? " " : " where ste.sessions_id in (:ids) ") + ") as a " + "where a.tags_name=te.name " ); if (!isFetchAll) { Set<Long> ids = sessionDataList.stream().map(SessionData::getId).collect(Collectors.toSet()); query.setParameter("ids", ids); } List<Object[]> sessionTags = query.getResultList(); for (Object[] tags : sessionTags) { Long sessionId = ((BigInteger) tags[0]).longValue(); tagMap.put(sessionId, new TagDto((String) tags[1], (String) tags[2])); } } sessionDataDtoList = new ArrayList<>(sessionDataList.size()); for (SessionData sessionData : sessionDataList) { sessionDataDtoList.add(createSessionDataDto(sessionData, userCommentMap.get(sessionData.getId()), new ArrayList<>(tagMap.get(sessionData.getId())))); } log.debug("There was loaded {} sessions data for {} ms", sessionDataDtoList.size(), System.currentTimeMillis() - timestamp); } catch (Exception e) { log.error( "Error was occurred during session data fetching for session Ids {}; start {}, length {}", e, new Object[]{sessionIds, start, length} ); throw new RuntimeException(e); } return sessionDataDtoList; } public List<SessionDataDto> getBySessionTagsName(int start, int length, Set<String> sessionTagNames) { if (!isTagsStorageAvailable) { return Collections.emptyList(); } checkArgument(start >= 0, "start is negative"); checkArgument(length >= 0, "length is negative"); checkNotNull(sessionTagNames, "sessionTagNames is null"); long timestamp = System.currentTimeMillis(); List<SessionDataDto> sessionDataDtoList; List<Long> sessionIds = new ArrayList<>(); List<BigInteger> ids; try { ids = entityManager.createNativeQuery("SELECT DISTINCT sd.sessions_id FROM SessionTagEntity AS sd WHERE sd.tags_name IN " + "(:sessionTagNames)") .setParameter("sessionTagNames", new ArrayList<>(sessionTagNames)).getResultList(); if (ids.isEmpty()) { return Collections.emptyList(); } sessionIds.addAll(ids.stream().map(BigInteger::longValue).collect(Collectors.toList())); List<SessionData> sessionDataList = (List<SessionData>) entityManager.createQuery("SELECT sd from SessionData as sd where sd.id in " + "(:sessionIds)") .setParameter("sessionIds", sessionIds) .setFirstResult(start) .setMaxResults(length) .getResultList(); if (sessionDataList.isEmpty()) { return Collections.emptyList(); } Map<Long, String> userCommentMap = Collections.EMPTY_MAP; if (isUserCommentStorageAvailable) { List<Object[]> userComments = entityManager.createQuery( "select smd.sessionData.id, smd.userComment from SessionMetaDataEntity as smd where smd.sessionData in (:sessionDataList)") .setParameter("sessionDataList", sessionDataList) .getResultList(); if (!userComments.isEmpty()) { userCommentMap = new HashMap<>(userComments.size()); for (Object[] objects : userComments) { userCommentMap.put((Long) objects[0], (String) objects[1]); } } } Map<Long, ArrayList<TagDto>> tagMap = Collections.EMPTY_MAP; if (isTagsStorageAvailable) { List<Object[]> sessionTags = entityManager.createNativeQuery("SELECT a.sessions_id, a.tags_name, te.description " + "FROM TagEntity AS te, (SELECT DISTINCT ste.sessions_id, ste.tags_name FROM SessionTagEntity AS ste WHERE ste.sessions_id " + "IN (:sessionIds)) AS a " + "WHERE a.tags_name=te.name") .setParameter("sessionIds", sessionIds) .getResultList(); tagMap = new HashMap<>(); for (Object[] tags : sessionTags) { if (!tagMap.containsKey(((BigInteger) tags[0]).longValue())) { tagMap.put(((BigInteger) tags[0]).longValue(), new ArrayList<>()); } tagMap.get(((BigInteger) tags[0]).longValue()).add(new TagDto((String) tags[1], (String) tags[2])); } } sessionDataDtoList = new ArrayList<>(sessionDataList.size()); for (SessionData sessionData : sessionDataList) { sessionDataDtoList.add(createSessionDataDto(sessionData, userCommentMap.get(sessionData.getId()), tagMap.get(sessionData.getId()))); } log.debug("There was loaded {} sessions data for {} ms", sessionDataDtoList.size(), System.currentTimeMillis() - timestamp); } catch (Exception e) { log.error("Error was occurred during session data fetching for session tags " + sessionTagNames + "; start " + start + ", length " + length, e); throw new RuntimeException(e); } return sessionDataDtoList; } private SessionDataDto createSessionDataDto(SessionData sessionData, String userComment, List<TagDto> tags) { return new SessionDataDto( sessionData.getId(), sessionData.getSessionId(), sessionData.getStartTime(), sessionData.getEndTime(), sessionData.getActiveKernels(), sessionData.getTaskExecuted(), sessionData.getTaskFailed(), HTMLFormatter.format(sessionData.getComment()), userComment, tags); } }