TimelineServiceImpl.java
/*
* Copyright (C) 2003-2008 eXo Platform SAS.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see<http://www.gnu.org/licenses/>.
*/
package org.exoplatform.services.cms.timeline.impl;
import org.exoplatform.container.xml.InitParams;
import org.exoplatform.services.cms.templates.TemplateService;
import org.exoplatform.services.cms.timeline.TimelineService;
import org.exoplatform.services.jcr.RepositoryService;
import org.exoplatform.services.jcr.core.ManageableRepository;
import org.exoplatform.services.jcr.ext.common.SessionProvider;
import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.query.Query;
import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
/**
* Created by The eXo Platform SARL
* Author : Dang Van Minh
* minh.dang@exoplatform.com
* Oct 22, 2009
* 8:19:51 AM
*/
public class TimelineServiceImpl implements TimelineService {
private static final Log LOG = ExoLogger.getLogger(TimelineServiceImpl.class.getName());
private static final String EXO_DATETIME = "exo:datetime";
private static final String EXO_MODIFIED_DATE = "exo:dateModified";
private static final String EXO_OWNER = "exo:owner";
private static final String SELECT_QUERY = "SELECT * FROM " + EXO_DATETIME + " WHERE ";
private static final String TIME_FORMAT_TAIL = "T00:00:00.000";
private static final DateTimeFormatter formatDateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private RepositoryService repositoryService_;
private TemplateService templateService_;
private int itemPerTimeline = 5;
public TimelineServiceImpl(RepositoryService repoService, TemplateService templateService,
InitParams initParams) throws Exception {
repositoryService_ = repoService;
templateService_ = templateService;
itemPerTimeline = Integer.parseInt(initParams.getValueParam("itemPerTimeline").getValue());
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisYear(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser) throws Exception {
return getDocumentsOfEarlierThisYear(nodePath, workspace, sessionProvider, userName, byUser, true);
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisYear(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser,
boolean isLimit) throws Exception {
List<Node> documentsOfYear = new ArrayList<Node>();
Session session = getSession(sessionProvider, workspace);
Calendar currentTime = new GregorianCalendar();
String strBeginningOfThisMonthTime = getStrBeginningOfThisMonthTime(currentTime);
String strBeginningOfThisYearTime = getStrBeginningOfThisYearTime(currentTime);
StringBuilder sb = new StringBuilder();
String pathPattern = buildPathPattern(nodePath);
sb.append(SELECT_QUERY);
if (pathPattern.length() > 0) {
sb.append(pathPattern).append(" AND ");
}
sb.append("((" + buildDocumentTypePattern() + ")")
.append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisYearTime + "')")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strBeginningOfThisMonthTime + "')");
if (byUser) {
sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
}
sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
NodeIterator nodeIter = result.getNodes();
while (nodeIter.hasNext()) {
documentsOfYear.add(nodeIter.nextNode());
}
return documentsOfYear;
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisMonth(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser) throws Exception {
return getDocumentsOfEarlierThisMonth(nodePath, workspace, sessionProvider, userName, byUser, true);
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisMonth(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser,
boolean isLimit) throws Exception {
List<Node> documentsOfMonth = new ArrayList<Node>();
Session session = getSession(sessionProvider, workspace);
Calendar currentTime = new GregorianCalendar();
String strBeginningOfThisWeekTime = getStrBeginningOfThisWeekTime(currentTime);
String strBeginningOfThisMonthTime = getStrBeginningOfThisMonthTime(currentTime);
StringBuilder sb = new StringBuilder();
String pathPattern = buildPathPattern(nodePath);
sb.append(SELECT_QUERY);
if (pathPattern.length() > 0) {
sb.append(pathPattern).append(" AND ");
}
sb.append("((" + buildDocumentTypePattern() + ")")
.append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisMonthTime + "')")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strBeginningOfThisWeekTime + "')");
if (byUser) {
sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
}
sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
NodeIterator nodeIter = result.getNodes();
while (nodeIter.hasNext()) {
documentsOfMonth.add(nodeIter.nextNode());
}
return documentsOfMonth;
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisWeek(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser) throws Exception {
return getDocumentsOfEarlierThisWeek(nodePath, workspace, sessionProvider, userName, byUser, true);
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfEarlierThisWeek(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser,
boolean isLimit) throws Exception {
List<Node> documentsOfWeek = new ArrayList<Node>();
Session session = getSession(sessionProvider, workspace);
Calendar currentTime = new GregorianCalendar();
String strYesterdayTime = getStrYesterdayTime(currentTime);
String strBeginningOfThisWeekTime = getStrBeginningOfThisWeekTime(currentTime);
StringBuilder sb = new StringBuilder();
String pathPattern = buildPathPattern(nodePath);
sb.append(SELECT_QUERY);
if(pathPattern.length() > 0) {
sb.append(pathPattern).append(" AND ");
}
sb.append("((" + buildDocumentTypePattern() + ")")
.append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisWeekTime + "')")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strYesterdayTime + "')");
if (byUser) {
sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
}
sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
NodeIterator nodeIter = result.getNodes();
while(nodeIter.hasNext()) {
documentsOfWeek.add(nodeIter.nextNode());
}
return documentsOfWeek;
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfYesterday(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser) throws Exception {
return getDocumentsOfYesterday(nodePath, workspace, sessionProvider, userName, byUser, true);
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfYesterday(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser,
boolean isLimit) throws Exception {
List<Node> documentsOfYesterday = new ArrayList<Node>();
Session session = getSession(sessionProvider, workspace);
Calendar currentTime = new GregorianCalendar();
String strTodayTime = getStrTodayTime(currentTime);
String strYesterdayTime = getStrYesterdayTime(currentTime);
StringBuilder sb = new StringBuilder();
String pathPattern = buildPathPattern(nodePath);
sb.append(SELECT_QUERY);
if(pathPattern.length() > 0) {
sb.append(pathPattern).append(" AND ");
}
sb.append("((" + buildDocumentTypePattern() + ")")
.append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strYesterdayTime + "')")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strTodayTime + "')");
if (byUser) {
sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
}
sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
NodeIterator nodeIter = result.getNodes();
while(nodeIter.hasNext()) {
documentsOfYesterday.add(nodeIter.nextNode());
}
return documentsOfYesterday;
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfToday(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser) throws Exception {
return getDocumentsOfToday(nodePath, workspace, sessionProvider, userName, byUser, true);
}
/**
* {@inheritDoc}
*/
public List<Node> getDocumentsOfToday(String nodePath,
String workspace,
SessionProvider sessionProvider,
String userName,
boolean byUser,
boolean isLimit) throws Exception {
List<Node> documentsOfToday = new ArrayList<Node>();
Session session = getSession(sessionProvider, workspace);
Calendar currentTime = new GregorianCalendar();
String strTodayTime = getStrTodayTime(currentTime);
StringBuilder sb = new StringBuilder();
String pathPattern = buildPathPattern(nodePath);
sb.append(SELECT_QUERY);
if(pathPattern.length() > 0) {
sb.append(pathPattern).append(" AND ");
}
sb.append("((" + buildDocumentTypePattern() + ")")
.append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
.append(" AND ")
.append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strTodayTime + "')");
if (byUser) {
sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
}
sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE).append(" DESC");
QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
NodeIterator nodeIter = result.getNodes();
while(nodeIter.hasNext()) {
documentsOfToday.add(nodeIter.nextNode());
}
return documentsOfToday;
}
private Session getSession(SessionProvider sessionProvider, String workspace) throws RepositoryException {
ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
return sessionProvider.getSession(workspace, manageableRepository);
}
private QueryResult executeQuery(Session session,
String statement,
String language,
boolean isLimt) throws Exception {
try {
QueryManager queryManager = session.getWorkspace().getQueryManager();
QueryImpl query = (QueryImpl) queryManager.createQuery(statement, language);
if (isLimt) {
query.setLimit(itemPerTimeline);
}
return query.execute();
} catch (Exception e) {
if (LOG.isErrorEnabled()) {
LOG.error("Can not execute query", e);
}
return null;
}
}
private String buildDocumentTypePattern() throws Exception {
List<String> documentFileTypes = templateService_.getAllDocumentNodeTypes();
StringBuilder sb = new StringBuilder();
for(String documentType : documentFileTypes) {
if(sb.length() > 0) sb.append(" OR ");
sb.append("jcr:primaryType='"+documentType+"'");
}
return sb.toString();
}
private String buildSymlinkDocumentTypePattern() throws Exception {
List<String> documentFileTypes = templateService_.getAllDocumentNodeTypes();
StringBuilder sb = new StringBuilder();
for(String documentType : documentFileTypes) {
if(sb.length() > 0) sb.append(" OR ");
sb.append("exo:primaryType='" + documentType + "'");
}
return sb.toString();
}
private String getStrTodayTime(Calendar calendar) {
String currentDate = LocalDateTime.ofInstant(calendar.getTime().toInstant(), calendar.getTimeZone().toZoneId()).format(formatDateTime);
return currentDate + TIME_FORMAT_TAIL;
}
private String buildPathPattern(String nodePath) {
if(nodePath.equals("/")) return "";
return "jcr:path LIKE '" + nodePath + "/%" + "'";
}
private String getStrYesterdayTime(Calendar calendar) {
Calendar yesterday = (Calendar)calendar.clone();
yesterday.add(Calendar.DATE, -1);
String yesterdayDate = LocalDateTime.ofInstant(yesterday.getTime().toInstant(), yesterday.getTimeZone().toZoneId()).format(formatDateTime);
return yesterdayDate + TIME_FORMAT_TAIL;
}
private String getStrBeginningOfThisWeekTime(Calendar calendar) {
Calendar monday = (Calendar)calendar.clone();
while (monday.get(Calendar.WEEK_OF_YEAR) == calendar.get(Calendar.WEEK_OF_YEAR)) {
monday.add(Calendar.DATE, -1);
}
monday.add(Calendar.DATE, 1);
String mondayDate = LocalDateTime.ofInstant(monday.getTime().toInstant(), monday.getTimeZone().toZoneId()).format(formatDateTime);
return mondayDate + TIME_FORMAT_TAIL;
}
private String getStrBeginningOfThisMonthTime(Calendar calendar) {
Calendar theFirst = (Calendar)calendar.clone();
theFirst.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1, 0, 0, 0);
String theFirstDate = LocalDateTime.ofInstant(theFirst.getTime().toInstant(), theFirst.getTimeZone().toZoneId()).format(formatDateTime);
return theFirstDate + TIME_FORMAT_TAIL;
}
private String getStrBeginningOfThisYearTime(Calendar calendar) {
Calendar theFirst = (Calendar)calendar.clone();
theFirst.set(calendar.get(Calendar.YEAR), 0, 1, 0, 0, 0);
String theFirstDate = LocalDateTime.ofInstant(theFirst.getTime().toInstant(), theFirst.getTimeZone().toZoneId()).format(formatDateTime);
return theFirstDate + TIME_FORMAT_TAIL;
}
/**
* Get the number of items per category displayed in Timeline view. this is
* get from initialize parameter of Timeline Service class If less than or
* equal zero then use default value 5 items per category.
*
* @return
*/
public int getItemPerTimeline() {
if (itemPerTimeline <= 0) {
return 5;
}
return itemPerTimeline;
}
}