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.io.PrintWriter; 020import java.io.StringWriter; 021import java.util.ArrayList; 022import java.util.List; 023 024import javax.jcr.Repository; 025import javax.jcr.Session; 026 027import org.apache.avalon.framework.component.Component; 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.avalon.framework.service.Serviceable; 031import org.apache.commons.lang.StringUtils; 032 033import org.ametys.cms.indexing.IndexingException; 034import org.ametys.cms.indexing.WorkspaceIndexer; 035import org.ametys.plugins.repository.AmetysObjectIterable; 036import org.ametys.runtime.plugin.component.AbstractLogEnabled; 037import org.ametys.web.WebConstants; 038import org.ametys.web.cache.CacheHelper; 039import org.ametys.web.cache.pageelement.PageElementCache; 040import org.ametys.web.indexing.SiteIndexer; 041import org.ametys.web.repository.site.Site; 042import org.ametys.web.repository.site.SiteManager; 043import org.ametys.web.skin.Skin; 044import org.ametys.web.skin.SkinsManager; 045 046/** 047 * Component for rebuild the live workspace, reindex all sitemaps and reset cache. 048 * Provide a way to rebuild the full live workspace, or only the live of a site. 049 */ 050public class RebuildLiveComponent extends AbstractLogEnabled implements Component, Serviceable 051{ 052 /** Avalon Role. */ 053 public static final String ROLE = RebuildLiveComponent.class.getName(); 054 055 private Repository _repository; 056 private LivePopulatorExtensionPoint _livePopulatorExtensionPoint; 057 private SitePopulator _sitePopulator; 058 private SiteIndexer _siteIndexer; 059 private WorkspaceIndexer _workspaceIndexer; 060 private SiteManager _siteManager; 061 private SkinsManager _skinsManager; 062 private PageElementCache _inputDataCache; 063 private PageElementCache _zoneItemCache; 064 065 @Override 066 public void service(ServiceManager manager) throws ServiceException 067 { 068 _siteIndexer = (SiteIndexer) manager.lookup(SiteIndexer.ROLE); 069 _repository = (Repository) manager.lookup(Repository.class.getName()); 070 _livePopulatorExtensionPoint = (LivePopulatorExtensionPoint) manager.lookup(LivePopulatorExtensionPoint.ROLE); 071 _sitePopulator = (SitePopulator) manager.lookup(SitePopulator.ROLE); 072 _workspaceIndexer = (WorkspaceIndexer) manager.lookup(WorkspaceIndexer.ROLE); 073 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 074 _skinsManager = (SkinsManager) manager.lookup(SkinsManager.ROLE); 075 _inputDataCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/inputData"); 076 _zoneItemCache = (PageElementCache) manager.lookup(PageElementCache.ROLE + "/zoneItem"); 077 } 078 079 /** 080 * Rebuild live workspace, index all sitemaps and reset cache. 081 * @throws Exception if an error occurs. 082 */ 083 public void rebuildLiveWorkspace() throws Exception 084 { 085 List<String> errors = new ArrayList<>(); 086 087 try 088 { 089 getLogger().info("Rebuilding live workspace started"); 090 091 long t0 = System.currentTimeMillis(); 092 093 errors.addAll(_populateLiveWorkspace()); 094 errors.addAll(_reindexLiveWorkspace()); 095 096 // Clear every site's cache. 097 AmetysObjectIterable<Site> siteIterable = _siteManager.getSites(); 098 for (Site site : siteIterable) 099 { 100 try 101 { 102 // TODO Clear only the live workspace? 103 _clearSiteCache(site); 104 } 105 catch (Throwable t) 106 { 107 errors.add("Failed to clear cache of site '" + site.getName() + "'\n" + t.getMessage()); 108 getLogger().error("Failed to clear cache of site '" + site.getName() + "'", t); 109 } 110 } 111 112 getLogger().info("Rebuilding live workspace ended in {} ms with {} error(s)", System.currentTimeMillis() - t0, errors.size()); 113 } 114 catch (Exception e) 115 { 116 throw new Exception("Failed to rebuild live workspace", e); 117 } 118 119 if (errors.size() > 0) 120 { 121 throw new Exception("Failed to rebuild live workspace with " + errors.size() + " error(s)\n\n--------------------------------------\n" + StringUtils.join(errors, "\n\n") + "\n--------------------------------------"); 122 } 123 } 124 125 private List<String> _populateLiveWorkspace() 126 { 127 List<String> errors = new ArrayList<>(); 128 129 Session session = null; 130 Session liveSession = null; 131 132 try 133 { 134 getLogger().info("Populating live workspace started"); 135 136 long t0 = System.currentTimeMillis(); 137 138 session = _repository.login(); 139 liveSession = _repository.login(WebConstants.LIVE_WORKSPACE); 140 141 // Synchronize other data 142 for (String id : _livePopulatorExtensionPoint.getExtensionsIds()) 143 { 144 getLogger().info("Populating live workspace using LivePopulator {} started", id); 145 146 try 147 { 148 LivePopulator populator = _livePopulatorExtensionPoint.getExtension(id); 149 150 errors.addAll(populator.populate(session, liveSession)); 151 152 if (liveSession.hasPendingChanges()) 153 { 154 liveSession.save(); 155 } 156 } 157 catch (Throwable t) 158 { 159 errors.add("Failed to populate live workspace with populator '" + id + "'\n" + t.getMessage()); 160 getLogger().error("Failed to populate live workspace with populator '" + id + "'", t); 161 } 162 163 getLogger().info("Populating live workspace using LivePopulator {} ended", id); 164 } 165 166 getLogger().info("Populating live workspace ended in {} ms", System.currentTimeMillis() - t0); 167 } 168 catch (Throwable t) 169 { 170 StringWriter sw = new StringWriter(); 171 t.printStackTrace(new PrintWriter(sw)); 172 173 errors.add("Failed to populate live workspace\n" + sw.toString()); 174 getLogger().error("Failed to populate live workspace", t); 175 } 176 finally 177 { 178 if (session != null) 179 { 180 session.logout(); 181 } 182 183 if (liveSession != null) 184 { 185 liveSession.logout(); 186 } 187 } 188 189 return errors; 190 } 191 192 private List<String> _reindexLiveWorkspace() 193 { 194 List<String> errors = new ArrayList<>(); 195 196 try 197 { 198 getLogger().info("Indexing Live workspace started"); 199 200 long t0 = System.currentTimeMillis(); 201 202 // Index the whole live workspace and not just every site. 203 _workspaceIndexer.index(WebConstants.LIVE_WORKSPACE); 204 205 getLogger().info("Indexing live workspace ended in {} ms", System.currentTimeMillis() - t0); 206 } 207 catch (IndexingException e) 208 { 209 errors.add("Failed to index live workspace\n" + e.getMessage()); 210 getLogger().error("Failed to index live workspace", e); 211 } 212 213 return errors; 214 } 215 216 /** 217 * Rebuild the live of a site, index all sitemaps and reset cache. 218 * @param site The site to be rebuilt 219 * @throws Exception if an error occurs. 220 */ 221 public void rebuildLive(Site site) throws Exception 222 { 223 String siteName = ""; 224 try 225 { 226 siteName = site.getName(); 227 228 Skin skin = _skinsManager.getSkin(site.getSkinId()); 229 assert skin != null; 230 231 getLogger().info("Rebuilding site {} started", siteName); 232 233 long t0 = System.currentTimeMillis(); 234 235 _populateSite(site, skin); 236 _reindexSite(site); 237 _clearSiteCache(site); 238 239 getLogger().info("Rebuilding site {} ended in {} ms", siteName, System.currentTimeMillis() - t0); 240 } 241 catch (Exception e) 242 { 243 throw new Exception("Failed to rebuild live workspace for site '" + siteName + "'", e); 244 } 245 } 246 247 private void _populateSite(Site site, Skin skin) throws Exception 248 { 249 String siteName = site.getName(); 250 251 getLogger().info("Populating site {} started", siteName); 252 253 long t0 = System.currentTimeMillis(); 254 255 _sitePopulator.populate(site, skin); 256 257 getLogger().info("Populating site {} ended in {} ms", siteName, System.currentTimeMillis() - t0); 258 } 259 260 private void _reindexSite(Site site) throws Exception 261 { 262 String siteName = site.getName(); 263 264 getLogger().info("Indexing site '{}' started", siteName); 265 266 long t0 = System.currentTimeMillis(); 267 268 // Reindex the site in the live workspace. 269 _siteIndexer.indexSite(site.getName(), WebConstants.LIVE_WORKSPACE); 270 271 getLogger().info("Indexing of site '{}' ended in {} ms", siteName, System.currentTimeMillis() - t0); 272 } 273 274 private void _clearSiteCache(Site site) throws Exception 275 { 276 String siteName = site.getName(); 277 278 getLogger().info("Clearing cache for site {} started", siteName); 279 280 long t0 = System.currentTimeMillis(); 281 282 CacheHelper.invalidateCache(site, getLogger()); 283 _inputDataCache.clear(null, siteName); 284 _zoneItemCache.clear(null, siteName); 285 286 getLogger().info("Clearing cache for site '{}' ended in {} ms", siteName, System.currentTimeMillis() - t0); 287 } 288}