001/* 002 * Copyright 2013 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.ametys.web.live; 018 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import javax.jcr.Repository; 025import javax.jcr.Session; 026import javax.mail.MessagingException; 027 028import org.apache.avalon.framework.component.Component; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.commons.lang.StringUtils; 033 034import org.ametys.cms.indexing.WorkspaceIndexer; 035import org.ametys.core.util.I18nUtils; 036import org.ametys.core.util.mail.SendMailHelper; 037import org.ametys.plugins.repository.AmetysObjectIterable; 038import org.ametys.runtime.config.Config; 039import org.ametys.runtime.i18n.I18nizableText; 040import org.ametys.runtime.plugin.component.AbstractLogEnabled; 041import org.ametys.web.WebConstants; 042import org.ametys.web.cache.CacheHelper; 043import org.ametys.web.cache.pageelement.PageElementCache; 044import org.ametys.web.indexing.SiteIndexer; 045import org.ametys.web.repository.site.Site; 046import org.ametys.web.repository.site.SiteManager; 047import org.ametys.web.skin.Skin; 048import org.ametys.web.skin.SkinsManager; 049 050/** 051 * Component for rebuild the live workspace, reindex all sitemaps and reset cache. 052 * Provide a way to rebuild the full live workspace, or only the live of a site. 053 */ 054public class RebuildLiveComponent extends AbstractLogEnabled implements Component, Serviceable 055{ 056 /** Avalon Role. */ 057 public static final String ROLE = RebuildLiveComponent.class.getName(); 058 059 private Repository _repository; 060 private LivePopulatorExtensionPoint _livePopulatorExtensionPoint; 061 private SitePopulator _sitePopulator; 062 private SiteIndexer _siteIndexer; 063 private WorkspaceIndexer _workspaceIndexer; 064 private SiteManager _siteManager; 065 private SkinsManager _skinsManager; 066 private PageElementCache _inputDataCache; 067 private PageElementCache _zoneItemCache; 068 private I18nUtils _i18nUtils; 069 070 @Override 071 public void service(ServiceManager manager) throws ServiceException 072 { 073 _siteIndexer = (SiteIndexer) manager.lookup(SiteIndexer.ROLE); 074 _repository = (Repository) manager.lookup(Repository.class.getName()); 075 _livePopulatorExtensionPoint = (LivePopulatorExtensionPoint) manager.lookup(LivePopulatorExtensionPoint.ROLE); 076 _sitePopulator = (SitePopulator) manager.lookup(SitePopulator.ROLE); 077 _workspaceIndexer = (WorkspaceIndexer) manager.lookup(WorkspaceIndexer.ROLE); 078 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 079 _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE); 080 _inputDataCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/inputData"); 081 _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); 082 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 083 } 084 085 /** 086 * Rebuild live workspace, index all sitemaps and reset cache. 087 * @return true if the all rebuilt succeed 088 * @throws Exception if an error occurs. 089 */ 090 public Map<String, String> rebuildLiveWorkspace() throws Exception 091 { 092 Map<String, String> errors = new HashMap<>(); 093 094 Session session = null; 095 Session liveSession = null; 096 097 if (getLogger().isInfoEnabled()) 098 { 099 getLogger().info("Rebuilding live workspace..."); 100 } 101 102 try 103 { 104 session = _repository.login(); 105 liveSession = _repository.login(WebConstants.LIVE_WORKSPACE); 106 107 // Synchronize other data 108 for (String id : _livePopulatorExtensionPoint.getExtensionsIds()) 109 { 110 if (getLogger().isInfoEnabled()) 111 { 112 getLogger().info("Populating live workspace using LivePopulator " + id); 113 } 114 115 LivePopulator populator = _livePopulatorExtensionPoint.getExtension(id); 116 117 populator.populate(session, liveSession); 118 119 if (liveSession.hasPendingChanges()) 120 { 121 liveSession.save(); 122 } 123 124 if (getLogger().isInfoEnabled()) 125 { 126 getLogger().info("LivePopulator " + id + "ended."); 127 } 128 } 129 130 if (getLogger().isInfoEnabled()) 131 { 132 getLogger().info("Live workspace populated"); 133 } 134 } 135 catch (Throwable t) 136 { 137 errors.put(null, t.getMessage()); 138 getLogger().error("Failed to populate live workspace", t); 139 140 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_ERROR_MAIL_SUBJECT"); 141 142 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/"); 143 List<String> i18nParams = new ArrayList<>(); 144 i18nParams.add(t.getMessage()); 145 i18nParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 146 147 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_ERROR_MAIL_BODY", i18nParams); 148 _sendErrorEmail(i18nSubject, i18nBody); 149 } 150 finally 151 { 152 if (session != null) 153 { 154 session.logout(); 155 } 156 157 if (liveSession != null) 158 { 159 liveSession.logout(); 160 } 161 } 162 163 if (getLogger().isInfoEnabled()) 164 { 165 getLogger().info("Reindexing live workspace."); 166 } 167 168 // Index the whole live workspace and not just every site. 169 _workspaceIndexer.index(WebConstants.LIVE_WORKSPACE); 170 171 if (getLogger().isInfoEnabled()) 172 { 173 getLogger().info("The live workspace was successfully indexed."); 174 } 175 176 // TODO Clear only the live workspace? 177 // Clear every site's cache. 178 AmetysObjectIterable<Site> siteIterable = _siteManager.getSites(); 179 180 for (Site site : siteIterable) 181 { 182 try 183 { 184 _clearCache(site); 185 } 186 catch (Exception e) 187 { 188 errors.put(site.getName(), e.getMessage()); 189 getLogger().error("Failed to rebuild live workspace for site '" + site.getName() + "'", e); 190 191 List<String> i18nSubjectParams = new ArrayList<>(); 192 i18nSubjectParams.add(site.getTitle()); 193 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_SUBJECT", i18nSubjectParams); 194 195 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/"); 196 List<String> i18nBodyParams = new ArrayList<>(); 197 i18nBodyParams.add(site.getTitle()); 198 i18nBodyParams.add(site.getName()); 199 i18nBodyParams.add(e.getMessage()); 200 i18nBodyParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 201 202 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_BODY", i18nBodyParams); 203 _sendErrorEmail(i18nSubject, i18nBody); 204 } 205 } 206 207 if (getLogger().isInfoEnabled()) 208 { 209 getLogger().info("Live workspace rebuilt"); 210 } 211 212 return errors; 213 } 214 215 /** 216 * Rebuild the live of a site, index all sitemaps and reset cache. 217 * @param site The site to be rebuilt 218 * @throws Exception if an error occurs. 219 */ 220 public void rebuildLive(Site site) throws Exception 221 { 222 String siteName = site.getName(); 223 224 Skin skin = _skinsManager.getSkin(site.getSkinId()); 225 assert skin != null; 226 227 try 228 { 229 if (getLogger().isInfoEnabled()) 230 { 231 getLogger().info("Rebuilding site " + siteName + " started"); 232 } 233 234 if (getLogger().isInfoEnabled()) 235 { 236 getLogger().info("Populating site " + siteName + " started"); 237 } 238 239 long t0 = System.currentTimeMillis(); 240 _sitePopulator.populate(site, skin); 241 242 if (getLogger().isInfoEnabled()) 243 { 244 getLogger().info("Populating site " + siteName + " ended in " + (System.currentTimeMillis() - t0) + " ms"); 245 } 246 247 _reindex(site); 248 _clearCache(site); 249 250 if (getLogger().isInfoEnabled()) 251 { 252 getLogger().info("Rebuilding site " + siteName + " ended in " + (System.currentTimeMillis() - t0) + " ms"); 253 } 254 } 255 catch (Exception e) 256 { 257 List<String> i18nSubjectParams = new ArrayList<>(); 258 i18nSubjectParams.add(site.getTitle()); 259 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_SUBJECT", i18nSubjectParams); 260 261 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValueAsString("cms.url"), "index.html"), "/"); 262 List<String> i18nBodyParams = new ArrayList<>(); 263 i18nBodyParams.add(site.getTitle()); 264 i18nBodyParams.add(site.getName()); 265 i18nBodyParams.add(e.getMessage()); 266 i18nBodyParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 267 268 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_BODY", i18nBodyParams); 269 _sendErrorEmail(i18nSubject, i18nBody); 270 271 throw new Exception("Failed to rebuild live workspace for site '" + site.getName() + "'", e); 272 } 273 } 274 275 private void _reindex(Site site) throws Exception 276 { 277 if (getLogger().isInfoEnabled()) 278 { 279 getLogger().info("Indexing site '" + site.getName() + "'."); 280 } 281 282 // Reindex the site in the live workspace. 283 _siteIndexer.indexSite(site.getName(), WebConstants.LIVE_WORKSPACE); 284 285 if (getLogger().isInfoEnabled()) 286 { 287 getLogger().info("Indexing of site '" + site.getName() + "' ended."); 288 } 289 } 290 291 private void _clearCache(Site site) throws Exception 292 { 293 if (getLogger().isInfoEnabled()) 294 { 295 getLogger().info("Clearing cache for site " + site.getName()); 296 } 297 298 CacheHelper.invalidateCache(site, getLogger()); 299 _inputDataCache.clear(null, site.getName()); 300 _zoneItemCache.clear(null, site.getName()); 301 } 302 303 private void _sendErrorEmail(I18nizableText i18nSubject, I18nizableText i18nBody) 304 { 305 String from = Config.getInstance().getValueAsString("smtp.mail.from"); 306 String sysadmin = Config.getInstance().getValueAsString("smtp.mail.sysadminto"); 307 308 if (StringUtils.isNotBlank(sysadmin)) 309 { 310 try 311 { 312 String subject = _i18nUtils.translate(i18nSubject); 313 String body = _i18nUtils.translate(i18nBody); 314 315 SendMailHelper.sendMail(subject, null, body, sysadmin, from); 316 } 317 catch (MessagingException e) 318 { 319 if (getLogger().isWarnEnabled()) 320 { 321 getLogger().warn("Could not send e-mail to " + sysadmin + " after build live failure", e); 322 } 323 } 324 } 325 } 326}