001/* 002 * Copyright 2015 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 */ 016package org.ametys.web.indexing.solr; 017 018import java.util.List; 019 020import org.apache.avalon.framework.service.ServiceException; 021import org.apache.avalon.framework.service.ServiceManager; 022import org.apache.solr.client.solrj.SolrClient; 023 024import org.ametys.cms.content.indexing.solr.SolrFieldNames; 025import org.ametys.cms.indexing.IndexingException; 026import org.ametys.cms.indexing.solr.SolrWorkspaceIndexer; 027import org.ametys.core.schedule.progression.ContainerProgressionTracker; 028import org.ametys.core.schedule.progression.SimpleProgressionTracker; 029import org.ametys.plugins.repository.AmetysObject; 030import org.ametys.plugins.repository.AmetysObjectIterable; 031import org.ametys.plugins.repository.AmetysObjectResolver; 032import org.ametys.plugins.repository.RepositoryConstants; 033import org.ametys.plugins.repository.TraversableAmetysObject; 034import org.ametys.plugins.repository.UnknownAmetysObjectException; 035import org.ametys.runtime.config.Config; 036import org.ametys.runtime.i18n.I18nizableText; 037import org.ametys.web.explorer.ResourceHelper; 038import org.ametys.web.indexing.SiteIndexer; 039import org.ametys.web.repository.site.Site; 040import org.ametys.web.repository.site.SiteManager; 041 042/** 043 * Web-specific component indexing a workspace in a Solr server. 044 */ 045public class SolrWebWorkspaceIndexer extends SolrWorkspaceIndexer 046{ 047 /** The site manager. */ 048 protected SiteManager _siteManager; 049 050 /** The site indexer. */ 051 protected SiteIndexer _siteIndexer; 052 053 /** The Ametys object resolver. */ 054 protected AmetysObjectResolver _resolver; 055 056 @Override 057 public void service(ServiceManager manager) throws ServiceException 058 { 059 super.service(manager); 060 061 _siteManager = (SiteManager) manager.lookup(SiteManager.ROLE); 062 _siteIndexer = (SiteIndexer) manager.lookup(SiteIndexer.ROLE); 063 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 064 } 065 066 private void _createProgressionTrackerStepsForDoIndex(ContainerProgressionTracker progressionTracker) 067 { 068 progressionTracker.addSimpleStep("unindexing", new I18nizableText("plugin.cms", "PLUGINS_CMS_SCHEDULER_GLOBAL_INDEXATION_UNINDEXING_DOCUMENT_SUB_STEP_LABEL")); 069 070 ContainerProgressionTracker sitesProgressionTracker = progressionTracker.addContainerStep("sites", new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_SITES_STEPS_LABEL")); 071 try (AmetysObjectIterable<Site> sites = _siteManager.getSites()) 072 { 073 for (Site site : sites) 074 { 075 sitesProgressionTracker.addContainerStep(site.getName(), new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_SITE_STEPS_LABEL", List.of(site.getName()))); 076 } 077 } 078 catch (Exception e) 079 { 080 // Ignoring, it will be rethrown just after 081 } 082 083 progressionTracker.addSimpleStep("contents", new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_CONTENT_STEP_LABEL")); 084 085 progressionTracker.addContainerStep("plugins", new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_NOSITES_CONTENTS_PLUGINS_STEPS_LABEL")); 086 087 progressionTracker.addSimpleStep("resources", new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_NOSITES_RESOURCES_STEPS_LABEL")); 088 089 _createAdditionalDocumentsProgressionTrackerSteps(progressionTracker); 090 091 progressionTracker.addSimpleStep("commitoptimize", new I18nizableText("plugin.cms", "PLUGINS_CMS_SCHEDULER_GLOBAL_INDEXATION_SAVING_COMMIT_AND_OPTIMIZE_SUB_STEP_LABEL")); 092 } 093 094 @Override 095 protected void doIndex(String workspaceName, ContainerProgressionTracker progressionTracker) throws IndexingException 096 { 097 _createProgressionTrackerStepsForDoIndex(progressionTracker); 098 099 SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName, false); 100 101 try (AmetysObjectIterable<Site> sites = _siteManager.getSites()) 102 { 103 // First, unindex all documents. 104 _solrIndexer.unindexAllDocuments(workspaceName, solrClient); 105 ((SimpleProgressionTracker) progressionTracker.getStep("unindexing")).increment(); 106 107 // Index each site. 108 ContainerProgressionTracker sitesProgressionTracker = progressionTracker.getStep("sites"); 109 for (Site site : sites) 110 { 111 _siteIndexer.indexSite(site.getName(), workspaceName, solrClient, sitesProgressionTracker.getStep(site.getName())); 112 } 113 114 // Index contents in the out-of-site content root. 115 indexContentRoot(workspaceName, solrClient, progressionTracker.getStep("contents")); 116 indexPluginsContentRoot(workspaceName, solrClient, progressionTracker.getStep("plugins")); 117 118 // Index shared resources. 119 indexSharedResources(workspaceName, solrClient, progressionTracker.getStep("resources")); 120 121 // Optionally index additional documents. 122 indexAdditionalDocuments(workspaceName, solrClient, progressionTracker); 123 124 _solrIndexer.commit(workspaceName, solrClient); 125 // Optimize once when done. 126 _solrIndexer.optimize(workspaceName, solrClient); 127 ((SimpleProgressionTracker) progressionTracker.getStep("commitoptimize")).increment(); 128 } 129 catch (Exception e) 130 { 131 getLogger().error("Error indexing the workspace '" + workspaceName + "'.", e); 132 throw new IndexingException("Error indexing the workspace '" + workspaceName + "'.", e); 133 } 134 } 135 136 /** 137 * Index the out-of-site contents. 138 * @param workspaceName The workspace name 139 * @param solrClient The solr client to use 140 * @param progressionTracker The progression tracker 141 * @throws Exception If an error occurs. 142 */ 143 protected void indexContentRoot(String workspaceName, SolrClient solrClient, SimpleProgressionTracker progressionTracker) throws Exception 144 { 145 try 146 { 147 TraversableAmetysObject contentRoot = _resolver.resolveByPath("/" + RepositoryConstants.NAMESPACE_PREFIX + ":contents"); 148 _solrIndexer.indexContents(contentRoot.getChildren(), workspaceName, true, solrClient, progressionTracker); 149 } 150 catch (UnknownAmetysObjectException e) 151 { 152 // Ignore if the content root doesn't exist in a workspace. 153 progressionTracker.setSize(0); 154 } 155 } 156 157 /** 158 * Index the contents stored by plugins 159 * @param workspaceName The workspace name 160 * @param solrClient The solr client to use 161 * @param progressionTracker The progression tracker 162 * @throws Exception If an error occurs. 163 */ 164 protected void indexPluginsContentRoot(String workspaceName, SolrClient solrClient, ContainerProgressionTracker progressionTracker) throws Exception 165 { 166 try 167 { 168 TraversableAmetysObject pluginsNode = _resolver.resolveByPath("/" + RepositoryConstants.NAMESPACE_PREFIX + ":plugins"); 169 170 for (AmetysObject pluginNode : pluginsNode.getChildren()) 171 { 172 if (pluginNode instanceof TraversableAmetysObject) 173 { 174 try 175 { 176 AmetysObject rootContents = ((TraversableAmetysObject) pluginNode).getChild(RepositoryConstants.NAMESPACE_PREFIX + ":contents"); 177 if (rootContents instanceof TraversableAmetysObject) 178 { 179 progressionTracker.addSimpleStep(pluginNode.getName(), new I18nizableText("plugin.web", "PLUGINS_WEB_SCHEDULABLE_SITE_INDEXATION_NOSITES_CONTENTS_PLUGIN_STEPS_LABEL", List.of(pluginNode.getName()))); 180 } 181 } 182 catch (UnknownAmetysObjectException e) 183 { 184 // Ignore if the content root doesn't exist in a plugin's node. 185 } 186 } 187 } 188 189 if (progressionTracker.getSize() == 0) 190 { 191 progressionTracker.addSimpleStep("noplugins", new I18nizableText("")); 192 progressionTracker.setSize(0); 193 } 194 else 195 { 196 for (AmetysObject pluginNode : pluginsNode.getChildren()) 197 { 198 if (pluginNode instanceof TraversableAmetysObject) 199 { 200 try 201 { 202 AmetysObject rootContents = ((TraversableAmetysObject) pluginNode).getChild(RepositoryConstants.NAMESPACE_PREFIX + ":contents"); 203 if (rootContents instanceof TraversableAmetysObject) 204 { 205 _solrIndexer.indexContents(((TraversableAmetysObject) rootContents).getChildren(), workspaceName, true, solrClient, progressionTracker.getStep(pluginNode.getName())); 206 } 207 } 208 catch (UnknownAmetysObjectException e) 209 { 210 // Ignore if the content root doesn't exist in a plugin's node. 211 } 212 213 } 214 } 215 } 216 } 217 catch (UnknownAmetysObjectException e) 218 { 219 // Ignore if the plugin's node doesn't exist in a workspace. 220 progressionTracker.addSimpleStep("empty", new I18nizableText("")).setSize(0); 221 } 222 } 223 224 225 /** 226 * Index the shared resources. 227 * @param workspaceName The workspace name 228 * @param solrClient The solr client to use 229 * @param progressionTracker The progression tracker 230 * @throws Exception If an error occurs. 231 */ 232 protected void indexSharedResources(String workspaceName, SolrClient solrClient, SimpleProgressionTracker progressionTracker) throws Exception 233 { 234 boolean useShared = Config.getInstance().getValue("resources.shared.folder"); 235 if (useShared) 236 { 237 try 238 { 239 TraversableAmetysObject sharedResources = _resolver.resolveByPath(ResourceHelper.SHARED_RESOURCE_PATH + "/all"); 240 _solrIndexer.indexResources(sharedResources.getChildren(), SolrFieldNames.TYPE_RESOURCE, sharedResources, workspaceName, solrClient, progressionTracker); 241 } 242 catch (UnknownAmetysObjectException e) 243 { 244 // Ignore if the shared resource root doesn't exist in a workspace. 245 progressionTracker.setSize(0); 246 } 247 } 248 else 249 { 250 progressionTracker.setSize(0); 251 } 252 } 253 254}