/* * Copyright 2012 Ixonos Plc, Finland. All rights reserved. * * This file is part of Kohti kumppanuutta. * * This file is licensed under GNU LGPL version 3. * Please see the 'license.txt' file in the root directory of the package you received. * If you did not receive a license, please contact the copyright holder * (http://www.ixonos.com/). * */ package fi.koku.services.utility.log.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fi.koku.KoKuFaultException; /** * Log related data access facilities implementation. Implements LogDAO interface. * * @author makinsu */ @Stateless public class LogDAOBean implements LogDAO { private static final Logger logger = LoggerFactory.getLogger(LogDAOBean.class); private LogUtils logUtils; @PersistenceContext private EntityManager em; public LogDAOBean() { logUtils = new LogUtils(); } @Override public int archiveLog(Date date){ // set the end time 1 day later so that everything added on the last day // will be archived. (Date has already been null-checked!) Date movedDate = logUtils.moveOneDay(date); // check if there is anything to archive Query selectQuery = em.createQuery("SELECT COUNT(l) FROM LogEntry l WHERE l.timestamp < :date"); // set the moved end date selectQuery.setParameter("date", movedDate); Long logEntryCount = (Long) selectQuery.getSingleResult(); logger.info("archive list size: " + logEntryCount); // there is nothing to archive, the portlet user will see an error message if (logEntryCount == 0) { return 0; } else { logger.info("insert log entries to archive log (enddate=" + date+")"); Query archiveQuery = em.createNativeQuery("INSERT INTO " + "log_archive (data_item_id, timestamp, user_pic, customer_pic, data_item_type, operation, client_system_id, message) " + "SELECT data_item_id, timestamp, user_pic, customer_pic, data_item_type, operation, client_system_id, message " + "FROM log WHERE timestamp < :date"); // set the moved end date archiveQuery.setParameter("date", movedDate); // execute the query int updateCount = archiveQuery.executeUpdate(); logger.info("Archived " + updateCount + " lines of log to log_archive table"); // If there is a Runtime error in archiving, no entries will be deleted from the database. // The portlet user will see an error message. // If the archiving went ok, delete the entries if(updateCount > 0){ Query deleteQuery = em.createNativeQuery("DELETE FROM log WHERE timestamp < :date"); // set the moved end date deleteQuery.setParameter("date", movedDate); int deletedRows = deleteQuery.executeUpdate(); logger.info("Deleted " + deletedRows + " rows from log table"); if (deletedRows != updateCount) { logger.error("the number of entries moved to archive is not the same as the number of deleted entries!"); } } return updateCount; } } /** * Find out the earliest entry to be archived */ @Override public Date getEarliest(Date date){ // get the timestamp of the earliest entry to be archived Query dateQuery = em.createNativeQuery("SELECT MIN(timestamp) FROM log WHERE timestamp <= :date"); dateQuery.setParameter("date", date); Date earliestDate = (Date)dateQuery.getSingleResult(); if(earliestDate == null){ logger.error("Could not get the timestamp of the earliest entry to be archived."); } return earliestDate; } /** * Write log (note: archive log is not written with this method!) */ @Override public void writeLog(LogEntry entry) { em.persist(entry); } /** * Write admin log. */ @Override public void writeAdminLog(AdminLogEntry entry) { em.persist(entry); } /** * Makes a query to the "normal" log and returns a list of LogEntries for * showing to the user in the portlet. (LOK-3) */ @Override public List<LogEntry> queryLog(LogQueryCriteria criteria) throws KoKuFaultException { StringBuilder sb = new StringBuilder(); List<Object[]> params = new ArrayList<Object[]>(); String entity = ""; // All four query parameters are mandatory: starttime, endime, // customerpic or userpic, dataitemtype. These fields are null-checked on the // portlet side but let's check them here again if (criteria.getStartTime() == null || criteria.getEndTime() == null || (criteria.getCustomerPic() == null &&criteria.getUserPic() == null) || criteria.getDataItemType() == null) { LogServiceErrorCode errorCode = LogServiceErrorCode.LOG_ERROR_INVALID_QUERY_CRITERIA; throw new KoKuFaultException(errorCode.getValue(), errorCode.getDescription()); } if (LogConstants.LOG_NORMAL.equalsIgnoreCase(criteria.getLogType())) { // tapahtumaloki entity = "LogEntry"; } else { logger.error("Wrong logtype in log query"); LogServiceErrorCode errorCode = LogServiceErrorCode.LOG_ERROR_INVALID_LOGTYPE; throw new KoKuFaultException(errorCode.getValue(), errorCode.getDescription()); } sb.append("SELECT e FROM " + entity + " e WHERE "); sb.append("e.timestamp >= :startTime"); params.add(new Object[] { "startTime", criteria.getStartTime() }); sb.append(" AND "); // set the end time 1 day later so that everything added on the last day // will be archived criteria.setEndTime(logUtils.moveOneDay(criteria.getEndTime())); sb.append("e.timestamp <= :endTime"); params.add(new Object[] { "endTime", criteria.getEndTime() }); sb.append(" AND "); if (criteria.getCustomerPic() != null ) { sb.append("e.customerPic = :pic"); params.add(new Object[] { "pic", criteria.getCustomerPic() }); } else if (criteria.getUserPic() != null ) { sb.append("e.userPic = :pic"); params.add(new Object[] { "pic", criteria.getUserPic() }); } // we can have concept with no value, this equals get all concepts if (criteria.getDataItemType() == null || criteria.getDataItemType().isEmpty()) { criteria.setDataItemType("*"); } if (criteria.getDataItemType() != null && !criteria.getDataItemType().isEmpty()) { sb.append(" AND "); String concept = criteria.getDataItemType(); // enable star queries (only star in the end can be used) if (concept.endsWith("*")){ int length = concept.length(); concept = concept.substring(0, length - 1) + "%"; sb.append("e.dataItemType LIKE :dataItemType"); } else{ sb.append("e.dataItemType = :dataItemType"); } params.add(new Object[] { "dataItemType", concept}); } if (params.size() == 0) { throw new IllegalArgumentException("Missing criteria for log query."); } Query q = em.createQuery(sb.toString()); // limit the number of results q.setMaxResults(LogConstants.MAX_QUERY_RESULTS); // build the query for (int i = 0; i < params.size(); i++) { q.setParameter((String) params.get(i)[0], params.get(i)[1]); } // query the database return q.getResultList(); } /** * Makes a query to the admin log and returns a list of AdminLogEntries for * showing to the super user in the portlet. (LOK-4) */ @Override public Collection<AdminLogEntry> queryAdminLog(LogQueryCriteria criteria) { StringBuilder sb = new StringBuilder(); List<Object[]> params = new ArrayList<Object[]>(); String entity = ""; // starttime and enddate are required and are null-checked in the portlet // let's check the criteria once again if (criteria == null || criteria.getStartTime() == null || criteria.getEndTime() == null) { logger.error("Admin log query criteria is null or invalid"); LogServiceErrorCode errorCode = LogServiceErrorCode.LOG_ERROR_INVALID_QUERY_CRITERIA; throw new KoKuFaultException(errorCode.getValue(), errorCode.getDescription()); } if (LogConstants.LOG_ADMIN.equalsIgnoreCase(criteria.getLogType())) { // seurantaloki entity = "AdminLogEntry"; } else { logger.error("Wrong logtype in admin log query"); LogServiceErrorCode errorCode = LogServiceErrorCode.LOG_ERROR_INVALID_LOGTYPE; throw new KoKuFaultException(errorCode.getValue(), errorCode.getDescription()); } // set the end time 1 day later so that everything added on the last day // will be found criteria.setEndTime(logUtils.moveOneDay(criteria.getEndTime())); sb.append("SELECT e FROM " + entity + " e WHERE "); sb.append("e.timestamp >= :startTime"); params.add(new Object[] { "startTime", criteria.getStartTime() }); sb.append(" AND "); sb.append("e.timestamp <= :endTime"); params.add(new Object[] { "endTime", criteria.getEndTime() }); if (params.size() == 0) { throw new IllegalArgumentException("missing query criteria"); } Query q = em.createQuery(sb.toString()); // limit the number of results q.setMaxResults(LogConstants.MAX_QUERY_RESULTS); // set parameters for (int i = 0; i < params.size(); i++) { q.setParameter((String) params.get(i)[0], params.get(i)[1]); } // query the database return q.getResultList(); } }