View Javadoc
1   package org.exoplatform.services.wcm.extensions.scheduler.impl;
2   
3   import java.lang.management.ManagementFactory;
4   import java.lang.management.RuntimeMXBean;
5   import java.text.SimpleDateFormat;
6   import java.util.Calendar;
7   import java.util.Date;
8   import java.util.HashMap;
9   
10  import javax.jcr.Node;
11  import javax.jcr.NodeIterator;
12  import javax.jcr.RepositoryException;
13  import javax.jcr.Session;
14  import javax.jcr.query.Query;
15  import javax.jcr.query.QueryManager;
16  import javax.jcr.query.QueryResult;
17  
18  import org.exoplatform.services.ecm.publication.PublicationPlugin;
19  import org.exoplatform.services.ecm.publication.PublicationService;
20  import org.exoplatform.services.jcr.RepositoryService;
21  import org.exoplatform.services.jcr.core.ManageableRepository;
22  import org.exoplatform.services.jcr.ext.common.SessionProvider;
23  import org.exoplatform.services.log.ExoLogger;
24  import org.exoplatform.services.log.Log;
25  import org.exoplatform.services.wcm.extensions.publication.lifecycle.authoring.AuthoringPublicationConstant;
26  import org.exoplatform.services.wcm.publication.PublicationDefaultStates;
27  import org.exoplatform.services.wcm.utils.WCMCoreUtils;
28  import org.quartz.Job;
29  import org.quartz.JobDataMap;
30  import org.quartz.JobExecutionContext;
31  import org.quartz.JobExecutionException;
32  
33  /**
34   * Created by The eXo Platform MEA Author : haikel.thamri@exoplatform.com
35   */
36  public class ChangeStateCronJobImpl implements Job {
37    private static final Log LOG                 = ExoLogger.getLogger(ChangeStateCronJobImpl.class.getName());
38  
39    private static final String START_TIME_PROPERTY = "publication:startPublishedDate";
40  
41    private static final String END_TIME_PROPERTY   = "publication:endPublishedDate";
42    
43    private static final int NORMAL_NODE = 0;
44    
45    private static final int STAGED_NODE = 1;
46    
47    private String              fromState           = null;
48  
49    private String              toState             = null;
50  
51    private String              predefinedPath      = null;
52  
53    private String              workspace           = null;
54    private String              contentPath         = null;
55    
56  
57    public void execute(JobExecutionContext context) throws JobExecutionException {
58      SessionProvider sessionProvider = null;
59      try {
60        RuntimeMXBean mx = ManagementFactory.getRuntimeMXBean();
61        if (mx.getUptime()>120000) {
62          if (LOG.isDebugEnabled()) LOG.debug("Start Execute ChangeStateCronJob");
63          if (fromState == null) {
64  
65            JobDataMap jdatamap = context.getJobDetail().getJobDataMap();
66  
67            fromState = jdatamap.getString("fromState");
68            toState = jdatamap.getString("toState");
69            predefinedPath = jdatamap.getString("predefinedPath");
70            String[] pathTab = predefinedPath.split(":");
71            workspace = pathTab[0];
72            contentPath = pathTab[1];
73          }
74          if (LOG.isDebugEnabled()) LOG.debug("Start Execute ChangeStateCronJob: change the State from " + fromState + " to "
75              + toState);
76          
77          sessionProvider = SessionProvider.createSystemProvider();
78          
79          String property = null;
80          if ("staged".equals(fromState) && "published".equals(toState)) {
81            property = START_TIME_PROPERTY;
82          } else if ("published".equals(fromState) && "unpublished".equals(toState)) {
83            property = END_TIME_PROPERTY;
84          }
85  
86          SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
87          Date now = Calendar.getInstance().getTime();
88          String currentTime = format.format(now);
89  
90          if (property != null) {
91            // appends trailing / if missing
92            if (contentPath != null) {
93              if (!contentPath.endsWith("/")) {
94                contentPath += "/";
95              }
96            }
97            
98            StringBuilder normalNodesStatement 
99                 = new StringBuilder().append("select * from nt:base where ").
100                                      append("(publication:currentState='").append(fromState).append("') ").
101                                      append(" and (").append(property).append(" IS NOT NULL )").
102                                      append(" and (").append(property).append(" < TIMESTAMP '").append(currentTime).append("') ").
103                                      append(" and (jcr:path like '").append(contentPath).append("%' )");
104           
105           StringBuilder stagedNodesStatement
106                = new StringBuilder().append("select * from nt:base where ").
107                                      append("(publication:currentState='").append(fromState).append("') ").
108                                      append(" and (").append(property).append(" IS NULL ) "). 
109                                      append(" and (jcr:path like '").append(contentPath).append("%' )");
110                                      
111           long normalCount = changeStateForNodes(sessionProvider, property, NORMAL_NODE, normalNodesStatement.toString());
112           long stagedCount = (START_TIME_PROPERTY.equals(property)) ? 
113                               changeStateForNodes(sessionProvider, property, STAGED_NODE, stagedNodesStatement.toString()) : 0;
114                               
115           long numberOfItemsToChange = normalCount + stagedCount;
116           
117           if (numberOfItemsToChange > 0) {
118             if (LOG.isDebugEnabled()) { 
119               LOG.debug(numberOfItemsToChange + " '" + fromState + "' candidates for state '" + toState
120                 + "' found in " + predefinedPath);
121             }
122           } else {
123             if (LOG.isDebugEnabled()) {
124               LOG.debug("no '" + fromState + "' content found in " + predefinedPath);
125             }
126           }
127           
128         }
129         if (LOG.isDebugEnabled()) LOG.debug("End Execute ChangeStateCronJob");
130       }
131 
132     } catch (RepositoryException ex) {
133       if (LOG.isErrorEnabled()) LOG.error("Repository not found. Ignoring :  " + ex.getMessage(), ex);
134     } catch (Exception ex) {
135       if (LOG.isErrorEnabled()) LOG.error("error when changing the state of the content : " + ex.getMessage(), ex);
136     } finally {
137       if (sessionProvider != null)
138         sessionProvider.close();
139     }
140   }
141   
142   private long changeStateForNodes(SessionProvider sessionProvider, String property, int nodeType, String statement) 
143   throws Exception {
144     long ret = 0;
145     RepositoryService repositoryService_ = WCMCoreUtils.getService(RepositoryService.class);
146     PublicationService publicationService = WCMCoreUtils.getService(PublicationService.class);
147     PublicationPlugin publicationPlugin = publicationService.getPublicationPlugins()
148     .get(AuthoringPublicationConstant.LIFECYCLE_NAME);
149     HashMap<String, String> context_ = new HashMap<String, String>();
150     
151     ManageableRepository manageableRepository = repositoryService_.getCurrentRepository();
152     if (manageableRepository == null) {
153       if (LOG.isDebugEnabled()) LOG.debug("Repository not found. Ignoring");
154       return 0;
155     }
156 
157     SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
158     
159     Session session = sessionProvider.getSession(workspace, manageableRepository);
160     QueryManager queryManager = session.getWorkspace().getQueryManager();
161     
162     Query query = queryManager.createQuery(statement, Query.SQL);
163     QueryResult queryResult = query.execute();
164     
165     for (NodeIterator iter = queryResult.getNodes(); iter.hasNext();) {
166       Node node_ = iter.nextNode();
167       
168       String path = node_.getPath();
169       if (!path.startsWith("/jcr:system")) {
170         if (NORMAL_NODE == nodeType) {
171           Date nodeDate = node_.getProperty(property).getDate().getTime();
172           if (LOG.isInfoEnabled()) LOG.info("'" + toState + "' " + node_.getPath() + " (" + property + "="
173               + format.format(nodeDate) + ")");
174   
175           if (PublicationDefaultStates.UNPUBLISHED.equals(toState)) {
176             if (node_.hasProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)) {
177               String liveRevisionProperty = node_.getProperty(AuthoringPublicationConstant.LIVE_REVISION_PROP)
178               .getString();
179               if (!"".equals(liveRevisionProperty)) {
180                 Node liveRevision = session.getNodeByUUID(liveRevisionProperty);
181                 if (liveRevision != null) {
182                   context_.put(AuthoringPublicationConstant.CURRENT_REVISION_NAME,
183                       liveRevision.getName());
184                 }
185               }
186             }
187   
188           }
189           publicationPlugin.changeState(node_, toState, context_);
190           ret ++;
191         } else {
192           if (LOG.isInfoEnabled()) LOG.info("'" + toState + "' " + node_.getPath());
193           publicationPlugin.changeState(node_, toState, context_);
194         }
195         if(START_TIME_PROPERTY.equals(property) && node_.hasProperty(START_TIME_PROPERTY)){
196           node_.getProperty(START_TIME_PROPERTY).remove();
197           node_.save();
198         }
199         if(END_TIME_PROPERTY.equals(property) && node_.hasProperty(END_TIME_PROPERTY)){
200           node_.getProperty(END_TIME_PROPERTY).remove();
201           node_.save();
202         }
203       }
204     }
205     
206     return ret;
207   }
208 }