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.IndexingException; 035import org.ametys.cms.indexing.WorkspaceIndexer; 036import org.ametys.core.util.I18nUtils; 037import org.ametys.core.util.mail.SendMailHelper; 038import org.ametys.plugins.repository.AmetysObjectIterable; 039import org.ametys.runtime.config.Config; 040import org.ametys.runtime.i18n.I18nizableText; 041import org.ametys.runtime.plugin.component.AbstractLogEnabled; 042import org.ametys.web.WebConstants; 043import org.ametys.web.cache.CacheHelper; 044import org.ametys.web.cache.pageelement.PageElementCache; 045import org.ametys.web.indexing.SiteIndexer; 046import org.ametys.web.repository.site.Site; 047import org.ametys.web.repository.site.SiteManager; 048import org.ametys.web.skin.Skin; 049import org.ametys.web.skin.SkinsManager; 050 051/** 052 * Component for rebuild the live workspace, reindex all sitemaps and reset cache. 053 * Provide a way to rebuild the full live workspace, or only the live of a site. 054 */ 055public class RebuildLiveComponent extends AbstractLogEnabled implements Component, Serviceable 056{ 057 /** Avalon Role. */ 058 public static final String ROLE = RebuildLiveComponent.class.getName(); 059 060 private Repository _repository; 061 private LivePopulatorExtensionPoint _livePopulatorExtensionPoint; 062 private SitePopulator _sitePopulator; 063 private SiteIndexer _siteIndexer; 064 private WorkspaceIndexer _workspaceIndexer; 065 private SiteManager _siteManager; 066 private SkinsManager _skinsManager; 067 private PageElementCache _inputDataCache; 068 private PageElementCache _zoneItemCache; 069 private I18nUtils _i18nUtils; 070 071 @Override 072 public void service(ServiceManager manager) throws ServiceException 073 { 074 _siteIndexer = (SiteIndexer) manager.lookup(SiteIndexer.ROLE); 075 _repository = (Repository) manager.lookup(Repository.class.getName()); 076 _livePopulatorExtensionPoint = (LivePopulatorExtensionPoint) manager.lookup(LivePopulatorExtensionPoint.ROLE); 077 _sitePopulator = (SitePopulator) manager.lookup(SitePopulator.ROLE); 078 _workspaceIndexer = (WorkspaceIndexer) manager.lookup(WorkspaceIndexer.ROLE); 079 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 080 _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE); 081 _inputDataCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/inputData"); 082 _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); 083 _i18nUtils = (I18nUtils) manager.lookup(I18nUtils.ROLE); 084 } 085 086 /** 087 * Rebuild live workspace, index all sitemaps and reset cache. 088 * @return true if the all rebuilt succeed 089 * @throws Exception if an error occurs. 090 */ 091 public Map<String, String> rebuildLiveWorkspace() throws Exception 092 { 093 Map<String, String> errors = new HashMap<>(); 094 095 Session session = null; 096 Session liveSession = null; 097 098 getLogger().info("Rebuilding live workspace..."); 099 100 try 101 { 102 session = _repository.login(); 103 liveSession = _repository.login(WebConstants.LIVE_WORKSPACE); 104 105 // Synchronize other data 106 for (String id : _livePopulatorExtensionPoint.getExtensionsIds()) 107 { 108 getLogger().info("Populating live workspace using LivePopulator {}", id); 109 110 LivePopulator populator = _livePopulatorExtensionPoint.getExtension(id); 111 112 populator.populate(session, liveSession); 113 114 if (liveSession.hasPendingChanges()) 115 { 116 liveSession.save(); 117 } 118 119 getLogger().info("LivePopulator {} ended.", id); 120 } 121 122 getLogger().info("Live workspace populated"); 123 } 124 catch (Throwable t) 125 { 126 errors.put(null, t.getMessage()); 127 getLogger().error("Failed to populate live workspace", t); 128 129 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_ERROR_MAIL_SUBJECT"); 130 131 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValue("cms.url"), "index.html"), "/"); 132 List<String> i18nParams = new ArrayList<>(); 133 i18nParams.add(t.getMessage()); 134 i18nParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 135 136 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDALL_ERROR_MAIL_BODY", i18nParams); 137 _sendErrorEmail(i18nSubject, i18nBody); 138 } 139 finally 140 { 141 if (session != null) 142 { 143 session.logout(); 144 } 145 146 if (liveSession != null) 147 { 148 liveSession.logout(); 149 } 150 } 151 152 getLogger().info("Reindexing live workspace."); 153 154 // Index the whole live workspace and not just every site. 155 try 156 { 157 _workspaceIndexer.index(WebConstants.LIVE_WORKSPACE); 158 } 159 catch (IndexingException e) 160 { 161 getLogger().error("An exception occured while indexing the whole LIVE workspace", e); 162 } 163 164 getLogger().info("The live workspace was successfully indexed."); 165 166 // TODO Clear only the live workspace? 167 // Clear every site's cache. 168 AmetysObjectIterable<Site> siteIterable = _siteManager.getSites(); 169 170 for (Site site : siteIterable) 171 { 172 try 173 { 174 _clearCache(site); 175 } 176 catch (Exception e) 177 { 178 errors.put(site.getName(), e.getMessage()); 179 getLogger().error("Failed to rebuild live workspace for site '" + site.getName() + "'", e); 180 181 List<String> i18nSubjectParams = new ArrayList<>(); 182 i18nSubjectParams.add(site.getTitle()); 183 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_SUBJECT", i18nSubjectParams); 184 185 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValue("cms.url"), "index.html"), "/"); 186 List<String> i18nBodyParams = new ArrayList<>(); 187 i18nBodyParams.add(site.getTitle()); 188 i18nBodyParams.add(site.getName()); 189 i18nBodyParams.add(e.getMessage()); 190 i18nBodyParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 191 192 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_BODY", i18nBodyParams); 193 _sendErrorEmail(i18nSubject, i18nBody); 194 } 195 } 196 197 getLogger().info("Live workspace rebuilt"); 198 199 return errors; 200 } 201 202 /** 203 * Rebuild the live of a site, index all sitemaps and reset cache. 204 * @param site The site to be rebuilt 205 * @throws Exception if an error occurs. 206 */ 207 public void rebuildLive(Site site) throws Exception 208 { 209 String siteName = site.getName(); 210 211 Skin skin = _skinsManager.getSkin(site.getSkinId()); 212 assert skin != null; 213 214 try 215 { 216 getLogger().info("Rebuilding site {} started", siteName); 217 218 getLogger().info("Populating site {} started", siteName); 219 220 long t0 = System.currentTimeMillis(); 221 _sitePopulator.populate(site, skin); 222 223 getLogger().info("Populating site {} ended in {} ms", siteName, System.currentTimeMillis() - t0); 224 225 _reindex(site); 226 _clearCache(site); 227 228 getLogger().info("Rebuilding site {} ended in {} ms", siteName, System.currentTimeMillis() - t0); 229 } 230 catch (Exception e) 231 { 232 List<String> i18nSubjectParams = new ArrayList<>(); 233 i18nSubjectParams.add(site.getTitle()); 234 I18nizableText i18nSubject = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_SUBJECT", i18nSubjectParams); 235 236 String cmsUrl = StringUtils.stripEnd(StringUtils.removeEndIgnoreCase(Config.getInstance().getValue("cms.url"), "index.html"), "/"); 237 List<String> i18nBodyParams = new ArrayList<>(); 238 i18nBodyParams.add(site.getTitle()); 239 i18nBodyParams.add(site.getName()); 240 i18nBodyParams.add(e.getMessage()); 241 i18nBodyParams.add(cmsUrl + "/_admin/_plugins/core/administrator/logs/view.html"); 242 243 I18nizableText i18nBody = new I18nizableText("plugin.web", "PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_BUILDPREVIEW_ERROR_MAIL_BODY", i18nBodyParams); 244 _sendErrorEmail(i18nSubject, i18nBody); 245 246 throw new Exception("Failed to rebuild live workspace for site '" + site.getName() + "'", e); 247 } 248 } 249 250 private void _reindex(Site site) throws Exception 251 { 252 String siteName = site.getName(); 253 254 getLogger().info("Indexing site '{}'.", siteName); 255 256 // Reindex the site in the live workspace. 257 _siteIndexer.indexSite(site.getName(), WebConstants.LIVE_WORKSPACE); 258 259 getLogger().info("Indexing of site '{}' ended.", siteName); 260 } 261 262 private void _clearCache(Site site) throws Exception 263 { 264 getLogger().info("Clearing cache for site {}", site.getName()); 265 266 CacheHelper.invalidateCache(site, getLogger()); 267 _inputDataCache.clear(null, site.getName()); 268 _zoneItemCache.clear(null, site.getName()); 269 } 270 271 private void _sendErrorEmail(I18nizableText i18nSubject, I18nizableText i18nBody) 272 { 273 String from = Config.getInstance().getValue("smtp.mail.from"); 274 String sysadmin = Config.getInstance().getValue("smtp.mail.sysadminto"); 275 276 if (StringUtils.isNotBlank(sysadmin)) 277 { 278 try 279 { 280 String subject = _i18nUtils.translate(i18nSubject); 281 String body = _i18nUtils.translate(i18nBody); 282 283 SendMailHelper.sendMail(subject, null, body, sysadmin, from); 284 } 285 catch (MessagingException e) 286 { 287 if (getLogger().isWarnEnabled()) 288 { 289 getLogger().warn("Could not send e-mail to " + sysadmin + " after build live failure", e); 290 } 291 } 292 } 293 } 294}