View Javadoc
1   /*
2    * Copyright (C) 2003-2008 eXo Platform SAS.
3    *
4    * This program is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Affero General Public License
6    * as published by the Free Software Foundation; either version 3
7    * of the License, or (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program; if not, see<http://www.gnu.org/licenses/>.
16   */
17  package org.exoplatform.services.cms.timeline.impl;
18  
19  import org.exoplatform.container.xml.InitParams;
20  import org.exoplatform.services.cms.templates.TemplateService;
21  import org.exoplatform.services.cms.timeline.TimelineService;
22  import org.exoplatform.services.jcr.RepositoryService;
23  import org.exoplatform.services.jcr.core.ManageableRepository;
24  import org.exoplatform.services.jcr.ext.common.SessionProvider;
25  import org.exoplatform.services.jcr.impl.core.query.QueryImpl;
26  import org.exoplatform.services.log.ExoLogger;
27  import org.exoplatform.services.log.Log;
28  
29  import javax.jcr.Node;
30  import javax.jcr.NodeIterator;
31  import javax.jcr.RepositoryException;
32  import javax.jcr.Session;
33  import javax.jcr.query.Query;
34  import javax.jcr.query.QueryManager;
35  import javax.jcr.query.QueryResult;
36  import java.time.LocalDateTime;
37  import java.time.format.DateTimeFormatter;
38  import java.util.ArrayList;
39  import java.util.Calendar;
40  import java.util.GregorianCalendar;
41  import java.util.List;
42  
43  /**
44   * Created by The eXo Platform SARL
45   * Author : Dang Van Minh
46   *          minh.dang@exoplatform.com
47   * Oct 22, 2009
48   * 8:19:51 AM
49   */
50  public class TimelineServiceImpl implements TimelineService {
51  
52    private static final Log LOG = ExoLogger.getLogger(TimelineServiceImpl.class.getName());
53    private static final String EXO_DATETIME = "exo:datetime";
54    private static final String EXO_MODIFIED_DATE = "exo:dateModified";
55    private static final String EXO_OWNER = "exo:owner";
56    private static final String SELECT_QUERY = "SELECT * FROM " + EXO_DATETIME + " WHERE ";
57    private static final String TIME_FORMAT_TAIL = "T00:00:00.000";
58    private static final DateTimeFormatter formatDateTime = DateTimeFormatter.ofPattern("yyyy-MM-dd");
59    private RepositoryService repositoryService_;
60    private TemplateService templateService_;
61    private int itemPerTimeline = 5;
62  
63    public TimelineServiceImpl(RepositoryService repoService, TemplateService templateService,
64        InitParams initParams) throws Exception {
65      repositoryService_ = repoService;
66      templateService_ = templateService;
67      itemPerTimeline = Integer.parseInt(initParams.getValueParam("itemPerTimeline").getValue());
68    }
69  
70    /**
71     * {@inheritDoc}
72     */
73    public List<Node> getDocumentsOfEarlierThisYear(String nodePath,
74                                                    String workspace,
75                                                    SessionProvider sessionProvider,
76                                                    String userName,
77                                                    boolean byUser) throws Exception {
78      return getDocumentsOfEarlierThisYear(nodePath, workspace, sessionProvider, userName, byUser, true);
79    }
80  
81    /**
82     * {@inheritDoc}
83     */
84    public List<Node> getDocumentsOfEarlierThisYear(String nodePath,
85                                                    String workspace,
86                                                    SessionProvider sessionProvider,
87                                                    String userName,
88                                                    boolean byUser,
89                                                    boolean isLimit) throws Exception {
90  
91      List<Node> documentsOfYear = new ArrayList<Node>();
92      Session session = getSession(sessionProvider, workspace);
93      Calendar currentTime = new GregorianCalendar();
94      String strBeginningOfThisMonthTime = getStrBeginningOfThisMonthTime(currentTime);
95      String strBeginningOfThisYearTime = getStrBeginningOfThisYearTime(currentTime);
96      StringBuilder sb = new StringBuilder();
97      String pathPattern = buildPathPattern(nodePath);
98      sb.append(SELECT_QUERY);
99      if (pathPattern.length() > 0) {
100       sb.append(pathPattern).append(" AND ");
101     }
102     sb.append("((" + buildDocumentTypePattern() + ")")
103       .append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
104       .append(" AND ")
105       .append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisYearTime + "')")
106       .append(" AND ")
107       .append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strBeginningOfThisMonthTime + "')");
108 
109     if (byUser) {
110       sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
111     }
112     sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
113 
114     QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
115     NodeIterator nodeIter = result.getNodes();
116     while (nodeIter.hasNext()) {
117       documentsOfYear.add(nodeIter.nextNode());
118     }
119     return documentsOfYear;
120   }
121 
122   /**
123    * {@inheritDoc}
124    */
125   public List<Node> getDocumentsOfEarlierThisMonth(String nodePath,
126                                                    String workspace,
127                                                    SessionProvider sessionProvider,
128                                                    String userName,
129                                                    boolean byUser) throws Exception {
130     return getDocumentsOfEarlierThisMonth(nodePath, workspace, sessionProvider, userName, byUser, true);
131   }
132   /**
133    * {@inheritDoc}
134    */
135   public List<Node> getDocumentsOfEarlierThisMonth(String nodePath,
136                                                    String workspace,
137                                                    SessionProvider sessionProvider,
138                                                    String userName,
139                                                    boolean byUser,
140                                                    boolean isLimit) throws Exception {
141 
142     List<Node> documentsOfMonth = new ArrayList<Node>();
143     Session session = getSession(sessionProvider, workspace);
144     Calendar currentTime = new GregorianCalendar();
145     String strBeginningOfThisWeekTime = getStrBeginningOfThisWeekTime(currentTime);
146     String strBeginningOfThisMonthTime = getStrBeginningOfThisMonthTime(currentTime);
147     StringBuilder sb = new StringBuilder();
148     String pathPattern = buildPathPattern(nodePath);
149     sb.append(SELECT_QUERY);
150     if (pathPattern.length() > 0) {
151       sb.append(pathPattern).append(" AND ");
152     }
153     sb.append("((" + buildDocumentTypePattern() + ")")
154       .append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
155       .append(" AND ")
156       .append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisMonthTime + "')")
157       .append(" AND ")
158       .append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strBeginningOfThisWeekTime + "')");
159 
160     if (byUser) {
161       sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
162     }
163     sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
164 
165     QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
166     NodeIterator nodeIter = result.getNodes();
167     while (nodeIter.hasNext()) {
168       documentsOfMonth.add(nodeIter.nextNode());
169     }
170     return documentsOfMonth;
171   }
172 
173   /**
174    * {@inheritDoc}
175    */
176   public List<Node> getDocumentsOfEarlierThisWeek(String nodePath,
177                                                   String workspace,
178                                                   SessionProvider sessionProvider,
179                                                   String userName,
180                                                   boolean byUser) throws Exception {
181     return getDocumentsOfEarlierThisWeek(nodePath, workspace, sessionProvider, userName, byUser, true);
182   }
183   /**
184    * {@inheritDoc}
185    */
186   public List<Node> getDocumentsOfEarlierThisWeek(String nodePath,
187                                                   String workspace,
188                                                   SessionProvider sessionProvider,
189                                                   String userName,
190                                                   boolean byUser,
191                                                   boolean isLimit) throws Exception {
192 
193     List<Node> documentsOfWeek = new ArrayList<Node>();
194     Session session = getSession(sessionProvider, workspace);
195     Calendar currentTime = new GregorianCalendar();
196     String strYesterdayTime = getStrYesterdayTime(currentTime);
197     String strBeginningOfThisWeekTime = getStrBeginningOfThisWeekTime(currentTime);
198     StringBuilder sb = new StringBuilder();
199     String pathPattern = buildPathPattern(nodePath);
200     sb.append(SELECT_QUERY);
201     if(pathPattern.length() > 0) {
202       sb.append(pathPattern).append(" AND ");
203     }
204     sb.append("((" + buildDocumentTypePattern() + ")")
205       .append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
206       .append(" AND ")
207       .append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strBeginningOfThisWeekTime + "')")
208       .append(" AND ")
209       .append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strYesterdayTime + "')");
210 
211     if (byUser) {
212       sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
213     }
214     sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
215 
216     QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
217     NodeIterator nodeIter = result.getNodes();
218     while(nodeIter.hasNext()) {
219       documentsOfWeek.add(nodeIter.nextNode());
220     }
221     return documentsOfWeek;
222   }
223 
224   /**
225    * {@inheritDoc}
226    */
227   public List<Node> getDocumentsOfYesterday(String nodePath,
228                                             String workspace,
229                                             SessionProvider sessionProvider,
230                                             String userName,
231                                             boolean byUser) throws Exception {
232     return getDocumentsOfYesterday(nodePath, workspace, sessionProvider, userName, byUser, true);
233   }
234 
235   /**
236    * {@inheritDoc}
237    */
238   public List<Node> getDocumentsOfYesterday(String nodePath,
239                                             String workspace,
240                                             SessionProvider sessionProvider,
241                                             String userName,
242                                             boolean byUser,
243                                             boolean isLimit) throws Exception {
244 
245     List<Node> documentsOfYesterday = new ArrayList<Node>();
246     Session session = getSession(sessionProvider, workspace);
247     Calendar currentTime = new GregorianCalendar();
248     String strTodayTime = getStrTodayTime(currentTime);
249     String strYesterdayTime = getStrYesterdayTime(currentTime);
250     StringBuilder sb = new StringBuilder();
251     String pathPattern = buildPathPattern(nodePath);
252     sb.append(SELECT_QUERY);
253     if(pathPattern.length() > 0) {
254       sb.append(pathPattern).append(" AND ");
255     }
256     sb.append("((" + buildDocumentTypePattern() + ")")
257       .append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
258       .append(" AND ")
259       .append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strYesterdayTime + "')")
260       .append(" AND ")
261       .append(" (" + EXO_MODIFIED_DATE + " < TIMESTAMP '" + strTodayTime + "')");
262 
263     if (byUser) {
264       sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
265     }
266     sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE);
267 
268     QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
269     NodeIterator nodeIter = result.getNodes();
270     while(nodeIter.hasNext()) {
271       documentsOfYesterday.add(nodeIter.nextNode());
272     }
273     return documentsOfYesterday;
274   }
275 
276   /**
277    * {@inheritDoc}
278    */
279   public List<Node> getDocumentsOfToday(String nodePath,
280                                         String workspace,
281                                         SessionProvider sessionProvider,
282                                         String userName,
283                                         boolean byUser) throws Exception {
284     return getDocumentsOfToday(nodePath, workspace, sessionProvider, userName, byUser, true);
285   }
286 
287   /**
288    * {@inheritDoc}
289    */
290   public List<Node> getDocumentsOfToday(String nodePath,
291                                         String workspace,
292                                         SessionProvider sessionProvider,
293                                         String userName,
294                                         boolean byUser,
295                                         boolean isLimit) throws Exception {
296     List<Node> documentsOfToday = new ArrayList<Node>();
297     Session session = getSession(sessionProvider, workspace);
298     Calendar currentTime = new GregorianCalendar();
299     String strTodayTime = getStrTodayTime(currentTime);
300     StringBuilder sb = new StringBuilder();
301     String pathPattern = buildPathPattern(nodePath);
302     sb.append(SELECT_QUERY);
303     if(pathPattern.length() > 0) {
304       sb.append(pathPattern).append(" AND ");
305     }
306     sb.append("((" + buildDocumentTypePattern() + ")")
307       .append(" OR (jcr:primaryType='exo:symlink' AND (" + buildSymlinkDocumentTypePattern() + ")))")
308       .append(" AND ")
309       .append(" (" + EXO_MODIFIED_DATE + " >= TIMESTAMP '" + strTodayTime + "')");
310     if (byUser) {
311       sb.append(" AND ").append(" (" + EXO_OWNER + " = '" + userName + "')");
312     }
313     sb.append(" ORDER BY ").append(EXO_MODIFIED_DATE).append(" DESC");
314 
315     QueryResult result = executeQuery(session, sb.toString(), Query.SQL, isLimit);
316     NodeIterator nodeIter = result.getNodes();
317     while(nodeIter.hasNext()) {
318       documentsOfToday.add(nodeIter.nextNode());
319     }
320     return documentsOfToday;
321   }
322 
323   private Session getSession(SessionProvider sessionProvider, String workspace) throws RepositoryException {
324     ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
325     return sessionProvider.getSession(workspace, manageableRepository);
326   }
327 
328   private QueryResult executeQuery(Session session,
329                                    String statement,
330                                    String language,
331                                    boolean isLimt) throws Exception {
332     try {
333       QueryManager queryManager = session.getWorkspace().getQueryManager();
334       QueryImpl query = (QueryImpl) queryManager.createQuery(statement, language);
335       if (isLimt) {
336         query.setLimit(itemPerTimeline);
337       }
338       return query.execute();
339     } catch (Exception e) {
340       if (LOG.isErrorEnabled()) {
341         LOG.error("Can not execute query", e);
342       }
343       return null;
344     }
345   }
346 
347   private String buildDocumentTypePattern() throws Exception {
348     List<String> documentFileTypes = templateService_.getAllDocumentNodeTypes();
349     StringBuilder sb = new StringBuilder();
350     for(String documentType : documentFileTypes) {
351       if(sb.length() > 0) sb.append(" OR ");
352       sb.append("jcr:primaryType='"+documentType+"'");
353     }
354     return sb.toString();
355   }
356 
357   private String buildSymlinkDocumentTypePattern() throws Exception {
358     List<String> documentFileTypes = templateService_.getAllDocumentNodeTypes();
359     StringBuilder sb = new StringBuilder();
360     for(String documentType : documentFileTypes) {
361       if(sb.length() > 0) sb.append(" OR ");
362       sb.append("exo:primaryType='" + documentType + "'");
363     }
364     return sb.toString();
365   }
366 
367   private String getStrTodayTime(Calendar calendar) {
368     String currentDate = LocalDateTime.ofInstant(calendar.getTime().toInstant(), calendar.getTimeZone().toZoneId()).format(formatDateTime);
369     return currentDate + TIME_FORMAT_TAIL;
370   }
371 
372   private String buildPathPattern(String nodePath) {
373     if(nodePath.equals("/")) return "";
374     return "jcr:path LIKE '" + nodePath + "/%" + "'";
375   }
376 
377   private String getStrYesterdayTime(Calendar calendar) {
378     Calendar yesterday = (Calendar)calendar.clone();
379     yesterday.add(Calendar.DATE, -1);
380     String yesterdayDate = LocalDateTime.ofInstant(yesterday.getTime().toInstant(), yesterday.getTimeZone().toZoneId()).format(formatDateTime);
381     return yesterdayDate + TIME_FORMAT_TAIL;
382   }
383 
384   private String getStrBeginningOfThisWeekTime(Calendar calendar) {
385     Calendar monday = (Calendar)calendar.clone();
386     while (monday.get(Calendar.WEEK_OF_YEAR) == calendar.get(Calendar.WEEK_OF_YEAR)) {
387       monday.add(Calendar.DATE, -1);
388     }
389     monday.add(Calendar.DATE, 1);
390     String mondayDate = LocalDateTime.ofInstant(monday.getTime().toInstant(), monday.getTimeZone().toZoneId()).format(formatDateTime);
391     return mondayDate + TIME_FORMAT_TAIL;
392   }
393 
394   private String getStrBeginningOfThisMonthTime(Calendar calendar) {
395     Calendar theFirst = (Calendar)calendar.clone();
396     theFirst.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), 1, 0, 0, 0);
397     String theFirstDate = LocalDateTime.ofInstant(theFirst.getTime().toInstant(), theFirst.getTimeZone().toZoneId()).format(formatDateTime);
398     return theFirstDate + TIME_FORMAT_TAIL;
399   }
400 
401   private String getStrBeginningOfThisYearTime(Calendar calendar) {
402     Calendar theFirst = (Calendar)calendar.clone();
403     theFirst.set(calendar.get(Calendar.YEAR), 0, 1, 0, 0, 0);
404     String theFirstDate = LocalDateTime.ofInstant(theFirst.getTime().toInstant(), theFirst.getTimeZone().toZoneId()).format(formatDateTime);
405     return theFirstDate + TIME_FORMAT_TAIL;
406   }
407 
408   /**
409    * Get the number of items per category displayed in Timeline view. this is
410    * get from initialize parameter of Timeline Service class If less than or
411    * equal zero then use default value 5 items per category.
412    *
413    * @return
414    */
415   public int getItemPerTimeline() {
416     if (itemPerTimeline <= 0) {
417       return 5;
418     }
419     return itemPerTimeline;
420   }
421 }