001/* 002 * Copyright 2016 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.cms.content.indexing.solr; 017 018import java.io.IOException; 019import java.util.ArrayList; 020import java.util.Date; 021import java.util.List; 022 023import org.apache.avalon.framework.component.Component; 024import org.apache.avalon.framework.service.ServiceException; 025import org.apache.avalon.framework.service.ServiceManager; 026import org.apache.avalon.framework.service.Serviceable; 027import org.apache.solr.client.solrj.SolrClient; 028import org.apache.solr.client.solrj.SolrServerException; 029import org.apache.solr.client.solrj.response.UpdateResponse; 030import org.apache.solr.client.solrj.util.ClientUtils; 031import org.apache.solr.common.SolrInputDocument; 032 033import org.ametys.cms.search.solr.SolrClientProvider; 034import org.ametys.plugins.repository.AmetysObject; 035import org.ametys.plugins.workflow.repository.WorkflowAwareAmetysObject; 036import org.ametys.plugins.workflow.support.WorkflowProvider; 037import org.ametys.plugins.workflow.support.WorkflowProvider.AmetysObjectWorkflow; 038import org.ametys.runtime.plugin.component.AbstractLogEnabled; 039 040import com.opensymphony.workflow.spi.Step; 041 042/** 043 * Component indexing the whole workflow of {@link AmetysObject}s. 044 */ 045public class SolrWorkflowIndexer extends AbstractLogEnabled implements Component, Serviceable, SolrFieldNames 046{ 047 /** The component role. */ 048 public static final String ROLE = SolrWorkflowIndexer.class.getName(); 049 050 /** The Solr client provider */ 051 protected SolrClientProvider _solrClientProvider; 052 053 /** The workflow provider. */ 054 protected WorkflowProvider _workflowProvider; 055 056 @Override 057 public void service(ServiceManager serviceManager) throws ServiceException 058 { 059 _solrClientProvider = (SolrClientProvider) serviceManager.lookup(SolrClientProvider.ROLE); 060 _workflowProvider = (WorkflowProvider) serviceManager.lookup(WorkflowProvider.ROLE); 061 } 062 063 /** 064 * Index the workflow history of an Ametys object. 065 * @param object The ametys object. 066 * @param workspaceName The workspace where to work in 067 * @throws SolrServerException If a solr error occurs. 068 * @throws IOException If an I/O error occurs while indexing. 069 */ 070 public void indexAmetysObjectWorkflow(WorkflowAwareAmetysObject object, String workspaceName) throws SolrServerException, IOException 071 { 072 indexAmetysObjectWorkflow(object, workspaceName, true); 073 } 074 075 /** 076 * Index the workflow history of an Ametys object. 077 * @param object The ametys object. 078 * @param workspaceName The workspace where to work in 079 * @param commit Whether to perform a commit after the indexation or not. 080 * @throws SolrServerException If a solr error occurs. 081 * @throws IOException If an I/O error occurs while indexing. 082 */ 083 public void indexAmetysObjectWorkflow(WorkflowAwareAmetysObject object, String workspaceName, boolean commit) throws SolrServerException, IOException 084 { 085 long time_0 = System.currentTimeMillis(); 086 getLogger().debug("Indexing the workflow of {}", object); 087 088 AmetysObjectWorkflow workflow = _workflowProvider.getAmetysObjectWorkflow(object); 089 090 long workflowId = object.getWorkflowId(); 091 List<Step> currentSteps = workflow.getCurrentSteps(workflowId); 092 List<Step> historySteps = workflow.getHistorySteps(workflowId); 093 094 String objectId = object.getId(); 095 096 List<SolrInputDocument> documents = new ArrayList<>(); 097 098 List<String> historyStepIds = indexSteps(historySteps, objectId, documents); 099 List<String> currentStepIds = indexSteps(currentSteps, objectId, documents); 100 101 indexWorkflowEntry(workflow, workflowId, objectId, historyStepIds, currentStepIds, documents); 102 103 SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName); 104 UpdateResponse solrResponse = solrClient.add(_solrClientProvider.getCollectionName(workspaceName), documents); 105 int status = solrResponse.getStatus(); 106 107 if (status != 0) 108 { 109 throw new IOException("Workflow history indexation error (status code=" + status + ")"); 110 } 111 112 if (commit) 113 { 114 solrClient.commit(_solrClientProvider.getCollectionName(workspaceName)); 115 } 116 117 getLogger().debug("Successfully indexed workflow of {} in {} ms", object, System.currentTimeMillis() - time_0); 118 } 119 120 private void indexWorkflowEntry(AmetysObjectWorkflow workflow, long workflowId, String objectId, List<String> historyStepIds, List<String> currentStepIds, List<SolrInputDocument> documents) 121 { 122 SolrInputDocument entryDoc = new SolrInputDocument(); 123 124 String id = objectId + "#workflow"; 125 126 String name = workflow.getWorkflowName(workflowId); 127 int state = workflow.getEntryState(workflowId); 128 129 entryDoc.addField(ID, id); 130 entryDoc.addField(DOCUMENT_TYPE, TYPE_WF_ENTRY); 131 entryDoc.addField(WORKFLOW_NAME, name); 132 entryDoc.addField(WORKFLOW_ENTRY_STATE, state); 133 entryDoc.addField(WORKFLOW_HISTORY_STEPS_DV, historyStepIds); 134 entryDoc.addField(WORKFLOW_CURRENT_STEPS_DV, currentStepIds); 135 136 documents.add(entryDoc); 137 } 138 139 private List<String> indexSteps(List<Step> steps, String objectId, List<SolrInputDocument> documents) 140 { 141 List<String> ids = new ArrayList<>(); 142 143 for (Step step : steps) 144 { 145 String id = indexStep(step, objectId, documents); 146 ids.add(id); 147 } 148 149 return ids; 150 } 151 152 private String indexStep(Step step, String objectId, List<SolrInputDocument> documents) 153 { 154 SolrInputDocument entryDoc = new SolrInputDocument(); 155 156 String id = objectId + "#step" + step.getId(); 157 int stepId = step.getStepId(); 158 int actionId = step.getActionId(); 159 String owner = step.getOwner(); 160 String caller = step.getCaller(); 161 Date startDate = step.getStartDate(); 162 Date dueDate = step.getDueDate(); 163 Date finishDate = step.getFinishDate(); 164 String status = step.getStatus(); 165 166 entryDoc.addField(ID, id); 167 entryDoc.addField(DOCUMENT_TYPE, TYPE_WF_STEP); 168 169 entryDoc.addField(WORKFLOW_STEP_ID, stepId); 170 entryDoc.addField(WORKFLOW_STEP_ACTIONID, actionId); 171 if (owner != null) 172 { 173 entryDoc.addField(WORKFLOW_STEP_OWNER, owner); 174 } 175 if (caller != null) 176 { 177 entryDoc.addField(WORKFLOW_STEP_CALLER, caller); 178 } 179 if (startDate != null) 180 { 181 entryDoc.addField(WORKFLOW_STEP_STARTDATE, startDate); 182 } 183 if (dueDate != null) 184 { 185 entryDoc.addField(WORKFLOW_STEP_DUEDATE, dueDate); 186 } 187 if (finishDate != null) 188 { 189 entryDoc.addField(WORKFLOW_STEP_FINISHDATE, finishDate); 190 } 191 if (status != null) 192 { 193 entryDoc.addField(WORKFLOW_STEP_STATUS, status); 194 } 195 196 documents.add(entryDoc); 197 198 return id; 199 } 200 201 /** 202 * Unindex the workflow history of an Ametys object. 203 * @param objectId The Ametys object ID. 204 * @param workspaceName The workspace where to work in 205 * @throws SolrServerException If a solr error occurs. 206 * @throws IOException If an I/O error occurs while indexing. 207 */ 208 public void unindexAmetysObjectWorkflow(String objectId, String workspaceName) throws SolrServerException, IOException 209 { 210 unindexAmetysObjectWorkflow(objectId, workspaceName, true); 211 } 212 213 /** 214 * Unindex the workflow history of an Ametys object. 215 * @param objectId The Ametys object ID. 216 * @param workspaceName The workspace where to work in 217 * @param commit Whether to perform a commit after the deletion or not. 218 * @throws SolrServerException If a solr error occurs. 219 * @throws IOException If an I/O error occurs while indexing. 220 */ 221 public void unindexAmetysObjectWorkflow(String objectId, String workspaceName, boolean commit) throws SolrServerException, IOException 222 { 223 // _documentType:(workflowEntry OR workflowStep) AND id:content\://xxx#* 224 StringBuilder query = new StringBuilder(); 225 query.append(DOCUMENT_TYPE).append(":(") 226 .append(TYPE_WF_ENTRY).append(" OR ").append(TYPE_WF_STEP) 227 .append(") AND id:").append(ClientUtils.escapeQueryChars(objectId + "#")).append("*"); 228 229 SolrClient solrClient = _solrClientProvider.getUpdateClient(workspaceName); 230 solrClient.deleteByQuery(_solrClientProvider.getCollectionName(workspaceName), query.toString()); 231 232 if (commit) 233 { 234 solrClient.commit(_solrClientProvider.getCollectionName(workspaceName)); 235 } 236 } 237 238}